All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.dreamhead.moco.rest.RestRequestDispatcher Maven / Gradle / Ivy

Go to download

Moco is an easy setup stub framework, mainly focusing on testing and integration.

There is a newer version: 1.5.0
Show newest version
package com.github.dreamhead.moco.rest;

import com.github.dreamhead.moco.HttpMethod;
import com.github.dreamhead.moco.HttpRequest;
import com.github.dreamhead.moco.Moco;
import com.github.dreamhead.moco.RequestMatcher;
import com.github.dreamhead.moco.ResponseHandler;
import com.github.dreamhead.moco.RestIdMatcher;
import com.github.dreamhead.moco.RestSetting;
import com.github.dreamhead.moco.handler.JsonResponseHandler;
import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import io.netty.handler.codec.http.HttpResponseStatus;

import static com.github.dreamhead.moco.Moco.by;
import static com.github.dreamhead.moco.Moco.status;
import static com.github.dreamhead.moco.Moco.uri;
import static com.github.dreamhead.moco.rest.RestIdMatchers.eq;
import static com.github.dreamhead.moco.util.URLs.join;
import static com.github.dreamhead.moco.util.URLs.resourceRoot;
import static com.google.common.base.Optional.absent;
import static com.google.common.base.Optional.of;

public final class RestRequestDispatcher {
    private static final ResponseHandler NOT_FOUND_HANDLER = status(HttpResponseStatus.NOT_FOUND.code());
    private static final ResponseHandler BAD_REQUEST_HANDLER = status(HttpResponseStatus.BAD_REQUEST.code());

    private final RestIdMatcher name;
    private final RequestMatcher allMatcher;
    private final RequestMatcher singleMatcher;
    private final CompositeRestSetting getAllSettings;
    private final CompositeRestSetting getSingleSettings;
    private final CompositeRestSetting postSettings;
    private final CompositeRestSetting putSettings;
    private final CompositeRestSetting deleteSettings;
    private final CompositeRestSetting headSettings;
    private final CompositeRestSetting headAllSettings;
    private final CompositeRestSetting patchSettings;
    private final FluentIterable subResourceSettings;

    public RestRequestDispatcher(final String name, final Iterable settings) {
        this.name = eq(name);

        this.getAllSettings = filterSettings(settings, RestAllSetting.class, HttpMethod.GET);
        this.getSingleSettings = filterSettings(settings, RestSingleSetting.class, HttpMethod.GET);
        this.postSettings = filterSettings(settings, RestAllSetting.class, HttpMethod.POST);
        this.putSettings = filterSettings(settings, RestSingleSetting.class, HttpMethod.PUT);
        this.deleteSettings = filterSettings(settings, RestSingleSetting.class, HttpMethod.DELETE);
        this.headSettings = filterSettings(settings, RestSingleSetting.class, HttpMethod.HEAD);
        this.headAllSettings = filterSettings(settings, RestAllSetting.class, HttpMethod.HEAD);
        this.patchSettings = filterSettings(settings, RestSingleSetting.class, HttpMethod.PATCH);
        this.subResourceSettings = filter(settings, SubResourceSetting.class);
        this.allMatcher = by(uri(resourceRoot(name)));
        this.singleMatcher = Moco.match(uri(join(resourceRoot(name), "[^/]*")));
    }

    private  CompositeRestSetting filterSettings(final Iterable settings,
                                                                                 final Class type,
                                                                                 final HttpMethod method) {
        return new CompositeRestSetting(filter(settings, type, method));
    }

    private  Function toInstance(final Class clazz) {
        return new Function() {
            @Override
            public T apply(final T input) {
                return clazz.cast(input);
            }
        };
    }

    private  FluentIterable filter(final Iterable settings,
                                                     final Class type,
                                                     final HttpMethod method) {
        return filter(settings, type)
                .filter(isForMethod(method));
    }

    private  FluentIterable filter(final Iterable settings,
                                                             final Class type) {
        return FluentIterable.from(settings)
                .filter(type)
                .transform(toInstance(type));
    }

    private  Predicate isForMethod(final HttpMethod method) {
        return new Predicate() {
            @Override
            public boolean apply(final T input) {
                return input.isSimple() && input.isFor(method);
            }
        };
    }

    private Predicate isJsonHandlers() {
        return new Predicate() {
            @Override
            public boolean apply(final SimpleRestSetting setting) {
                return setting.getHandler() instanceof JsonResponseHandler;
            }
        };
    }

    private Function toJsonHandler() {
        return new Function() {
            @Override
            public JsonResponseHandler apply(final SimpleRestSetting setting) {
                return JsonResponseHandler.class.cast(setting.getHandler());
            }
        };
    }

    private Function toPojo() {
        return new Function() {
            @Override
            public Object apply(final JsonResponseHandler handler) {
                return handler.getPojo();
            }
        };
    }

    private Optional getSingleOrAllHandler(final HttpRequest httpRequest,
                                                            final CompositeRestSetting single,
                                                            final CompositeRestSetting all,
                                                            final RestIdMatcher name) {
        Optional singleHandler = single.getMatched(name, httpRequest);
        if (singleHandler.isPresent()) {
            return singleHandler;
        }

        Optional allHandler = all.getMatched(name, httpRequest);
        if (allHandler.isPresent()) {
            return allHandler;
        }

        return absent();
    }

    private Optional getHeadHandler(final HttpRequest httpRequest) {
        Optional handler = getSingleOrAllHandler(httpRequest,
                headSettings,
                headAllSettings,
                name);
        if (handler.isPresent()) {
            return handler;
        }

        return of(NOT_FOUND_HANDLER);
    }

    private Optional getGetHandler(final HttpRequest httpRequest) {
        Optional matchedSetting = getSingleOrAllHandler(httpRequest,
                getSingleSettings,
                getAllSettings, name);
        if (matchedSetting.isPresent()) {
            return matchedSetting;
        }

        if (allMatcher.match(httpRequest)) {
            FluentIterable settings = FluentIterable.from(getSingleSettings.getSettings());
            if (!settings.isEmpty() && settings.allMatch(isJsonHandlers())) {
                ImmutableList objects = settings
                        .transform(toJsonHandler())
                        .transform(toPojo()).toList();
                return of(Moco.toJson(objects));
            }
        }

        return of(NOT_FOUND_HANDLER);
    }

    private Optional getPostHandler(final HttpRequest request) {
        Optional handler = postSettings.getMatched(name, request);
        if (handler.isPresent()) {
            return handler;
        }

        if (singleMatcher.match(request)) {
            return of(NOT_FOUND_HANDLER);
        }

        return of(BAD_REQUEST_HANDLER);
    }

    private Optional getSingleResponseHandler(
            final CompositeRestSetting settings,
            final HttpRequest httpRequest) {
        Optional handler = settings.getMatched(name, httpRequest);
        if (handler.isPresent()) {
            return handler;
        }

        return of(NOT_FOUND_HANDLER);
    }

    public Optional getResponseHandler(final HttpRequest httpRequest) {
        if (allMatcher.match(httpRequest) || this.singleMatcher.match(httpRequest)) {
            return doGetResponseHandler(httpRequest);
        }

        return getSubResponseHandler(httpRequest);
    }

    private Optional getSubResponseHandler(final HttpRequest httpRequest) {
        for (SubResourceSetting subResourceSetting : subResourceSettings) {
            Optional matched = subResourceSetting.getMatched(name, httpRequest);
            if (matched.isPresent()) {
                return matched;
            }
        }

        return absent();
    }

    private Optional doGetResponseHandler(final HttpRequest httpRequest) {
        HttpMethod method = httpRequest.getMethod();
        if (HttpMethod.GET == method) {
            return getGetHandler(httpRequest);
        }

        if (HttpMethod.POST == method) {
            return getPostHandler(httpRequest);
        }

        if (HttpMethod.PUT == method) {
            return getSingleResponseHandler(putSettings, httpRequest);
        }

        if (HttpMethod.DELETE == method) {
            return getSingleResponseHandler(deleteSettings, httpRequest);
        }

        if (HttpMethod.HEAD == method) {
            return getHeadHandler(httpRequest);
        }

        if (HttpMethod.PATCH == method) {
            return getSingleResponseHandler(patchSettings, httpRequest);
        }

        return absent();
    }
}