mousio.etcd4j.transport.EtcdResponseHandler.java Source code

Java tutorial

Introduction

Here is the source code for mousio.etcd4j.transport.EtcdResponseHandler.java

Source

/*
 * Copyright (c) 2015, contributors as indicated by the @author tags.
 *
 * 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 mousio.etcd4j.transport;

import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.util.CharsetUtil;
import io.netty.util.concurrent.Promise;
import mousio.client.exceptions.PrematureDisconnectException;
import mousio.etcd4j.requests.EtcdRequest;
import mousio.etcd4j.responses.EtcdAuthenticationException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

/**
 * @author Jurriaan Mous
 * @author Luca Burgazzoli
 *
 * Handles etcd responses
 *
 * @param <R> Response type
 */
class EtcdResponseHandler<R> extends SimpleChannelInboundHandler<FullHttpResponse> {
    private static final Logger logger = LoggerFactory.getLogger(EtcdResponseHandler.class);

    private static final CharSequence HTTP_HEADER_LOCATION = "Location";

    protected final Promise<R> promise;
    protected final EtcdNettyClient client;
    protected final EtcdRequest<R> request;

    private boolean isRetried;

    /**
     * Constructor
     *
     * @param etcdNettyClient the client handling connections
     * @param etcdRequest     request
     */
    @SuppressWarnings("unchecked")
    public EtcdResponseHandler(EtcdNettyClient etcdNettyClient, EtcdRequest<R> etcdRequest) {
        this.client = etcdNettyClient;
        this.request = etcdRequest;
        this.promise = etcdRequest.getPromise().getNettyPromise();
        this.isRetried = false;
    }

    /**
     * Set if the connection is retried.
     * If true the promise will not fail on unregistering this handler.
     *
     * @param retried true if request is being retried.
     */
    public void retried(boolean retried) {
        this.isRetried = retried;
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        if (!isRetried && !promise.isDone()) {
            this.request.getPromise().handleRetry(new PrematureDisconnectException());
        }
        super.channelUnregistered(ctx);
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, FullHttpResponse response) throws Exception {
        if (logger.isDebugEnabled()) {
            logger.debug("Received " + response.status().code() + " for " + this.request.getMethod().name() + " "
                    + this.request.getUri());
        }

        if (response.status().equals(HttpResponseStatus.MOVED_PERMANENTLY)
                || response.status().equals(HttpResponseStatus.TEMPORARY_REDIRECT)) {
            if (response.headers().contains(HTTP_HEADER_LOCATION)) {
                this.request.setUrl(response.headers().get(HTTP_HEADER_LOCATION));
                this.client.connect(this.request);
                // Closing the connection which handled the previous request.
                ctx.close();
                if (logger.isDebugEnabled()) {
                    logger.debug("redirect for " + this.request.getHttpRequest().uri() + " to "
                            + response.headers().get(HTTP_HEADER_LOCATION));
                }
            } else {
                this.promise.setFailure(new Exception("Missing Location header on redirect"));
            }
        }
        if (response.status().equals(HttpResponseStatus.UNAUTHORIZED)) {
            this.promise
                    .setFailure(new EtcdAuthenticationException(response.content().toString(CharsetUtil.UTF_8)));
        } else {
            if (!response.content().isReadable()) {
                // If connection was accepted maybe response has to be waited for
                if (response.status().equals(HttpResponseStatus.OK)
                        || response.status().equals(HttpResponseStatus.ACCEPTED)
                        || response.status().equals(HttpResponseStatus.CREATED)) {
                    this.client.connect(this.request);
                    return;
                }
                this.promise
                        .setFailure(new IOException("Content was not readable. HTTP Status: " + response.status()));
            }

            try {
                this.promise
                        .setSuccess(request.getResponseDecoder().decode(response.headers(), response.content()));
            }
            // Catches both parsed EtcdExceptions and parsing exceptions
            catch (Exception e) {
                this.promise.setFailure(e);
            }
        }
    }
}