
com.spotify.apollo.request.RequestRunnableImpl Maven / Gradle / Ivy
/*
* -\-\-
* Spotify Apollo API Implementations
* --
* Copyright (C) 2013 - 2015 Spotify AB
* --
* 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 com.spotify.apollo.request;
import com.google.common.base.Joiner;
import com.google.common.collect.Sets;
import com.spotify.apollo.Request;
import com.spotify.apollo.Response;
import com.spotify.apollo.StatusType;
import com.spotify.apollo.dispatch.Endpoint;
import com.spotify.apollo.route.ApplicationRouter;
import com.spotify.apollo.route.InvalidUriException;
import com.spotify.apollo.route.RuleMatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collection;
import java.util.Optional;
import java.util.function.BiConsumer;
import okio.ByteString;
import static com.spotify.apollo.Response.forStatus;
import static com.spotify.apollo.Status.BAD_REQUEST;
import static com.spotify.apollo.Status.INTERNAL_SERVER_ERROR;
import static com.spotify.apollo.Status.METHOD_NOT_ALLOWED;
import static com.spotify.apollo.Status.NOT_FOUND;
import static com.spotify.apollo.Status.NO_CONTENT;
/**
* Runs a request in an application and allows failing the request.
*/
class RequestRunnableImpl implements RequestRunnable {
private static final Logger LOG = LoggerFactory.getLogger(RequestRunnableImpl.class);
private final OngoingRequest ongoingRequest;
private final ApplicationRouter applicationRouter;
RequestRunnableImpl(OngoingRequest ongoingRequest, ApplicationRouter applicationRouter) {
this.ongoingRequest = ongoingRequest;
this.applicationRouter = applicationRouter;
}
/**
* Route the request to a matching endpoint and continue with the {@link BiConsumer}
*/
@Override
public void run(BiConsumer> matchContinuation) {
try {
matchAndRun(matchContinuation);
} catch (Exception e) {
LOG.error("Exception when handling request", e);
// ensure that we reply with a server error, if possible
ongoingRequest.reply(forStatus(INTERNAL_SERVER_ERROR));
}
}
private void matchAndRun(BiConsumer> matchContinuation) {
final Request request = ongoingRequest.request();
final Optional> match;
try {
match = applicationRouter.match(request);
} catch (InvalidUriException e) {
LOG.warn("bad uri {} {} {}", request.method(), request.uri(), BAD_REQUEST, e);
ongoingRequest.reply(forStatus(BAD_REQUEST));
return;
}
if (!match.isPresent()) {
Collection methods = applicationRouter.getMethodsForValidRules(request);
if (methods.isEmpty()) {
LOG.warn("not found {} {} {}", request.method(), request.uri(), NOT_FOUND);
ongoingRequest.reply(forStatus(NOT_FOUND));
} else {
StatusType statusCode;
if ("OPTIONS".equals(request.method())) {
statusCode = NO_CONTENT;
} else {
statusCode = METHOD_NOT_ALLOWED;
LOG.warn("wrong method {} {} {}", request.method(), request.uri(), statusCode);
}
methods = Sets.newTreeSet(methods);
methods.add("OPTIONS");
ongoingRequest.reply(
Response.forStatus(statusCode)
.withHeader("Allow", Joiner.on(", ").join(methods)));
}
return;
}
matchContinuation.accept(ongoingRequest, match.get());
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy