Package voldemort.rest.coordinator.admin

Source Code of voldemort.rest.coordinator.admin.CoordinatorAdminRequestHandler

/*
* Copyright 2013 LinkedIn, Inc
*
* 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 voldemort.rest.coordinator.admin;

import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH;
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.NOT_FOUND;
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.OK;
import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1;

import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.log4j.Logger;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelHandler;
import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
import org.jboss.netty.handler.codec.http.HttpChunk;
import org.jboss.netty.handler.codec.http.HttpMethod;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.handler.codec.http.HttpResponse;
import org.jboss.netty.handler.codec.http.HttpResponseStatus;

import voldemort.rest.coordinator.config.ClientConfigUtil;
import voldemort.rest.coordinator.config.StoreClientConfigService;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

public class CoordinatorAdminRequestHandler extends SimpleChannelHandler {

    private static final String STORE_OPS_NAMESPACE = "store-client-config-ops";
    private final StoreClientConfigService storeClientConfigs;
    public HttpRequest request;
    private boolean readingChunks;
    private final Logger logger = Logger.getLogger(CoordinatorAdminRequestHandler.class);

    public CoordinatorAdminRequestHandler(StoreClientConfigService storeClientConfigs) {
        this.storeClientConfigs = storeClientConfigs;
    }

    @Override
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent messageEvent)
            throws Exception {
        if(!readingChunks) {
            HttpRequest request = this.request = (HttpRequest) messageEvent.getMessage();
            String requestURI = this.request.getUri();
            if (logger.isDebugEnabled()) {
                logger.debug("Admin Request URI: " + requestURI);
            }
            if(request.isChunked()) {
                readingChunks = true;
            } else {
                String[] requestUriSegments = requestURI.split("/");
                HttpResponse response;
                if(requestUriSegments.length > 0
                   && requestUriSegments[1].equals(STORE_OPS_NAMESPACE)) {
                    List<String> storeList = Lists.newArrayList();
                    if(requestUriSegments.length > 2) {
                        String csvStoreList = requestUriSegments[2];
                        String[] storeArray = csvStoreList.split(",");
                        storeList = Lists.newArrayList(storeArray);
                    }
                    HttpMethod httpMethod = request.getMethod();
                    if(httpMethod.equals(HttpMethod.GET)) {
                        response = handleGet(storeList);
                    } else if(httpMethod.equals(HttpMethod.POST)) {
                        Map<String, Properties> configsToPut = Maps.newHashMap();
                        ChannelBuffer content = this.request.getContent();
                        if(content != null) {
                            byte[] postBody = new byte[content.capacity()];
                            content.readBytes(postBody);
                            configsToPut = ClientConfigUtil.readMultipleClientConfigAvro(new String(postBody));
                        }
                        response = handlePut(configsToPut);
                    } else if(httpMethod.equals(HttpMethod.DELETE)) {
                        if(storeList.size() == 0) {
                            response = handleBadRequest(
                                    "Cannot delete config for all stores. Please specify at least one store name.");
                        } else {
                            response = handleDelete(storeList);
                        }
                    } else { // Bad HTTP method
                        response = handleBadRequest(
                                "Unsupported HTTP method. Only GET, POST and DELETE are supported.");
                    }
                } else { // Bad namespace
                    response = handleBadRequest(
                            "Unsupported namespace. Only /" + STORE_OPS_NAMESPACE + "/ is supported.");
                }
                messageEvent.getChannel().write(response);
            }
        } else {
            HttpChunk chunk = (HttpChunk) messageEvent.getMessage();
            if(chunk.isLast()) {
                readingChunks = false;
            }
        }
    }

    private HttpResponse handleGet(List<String> storeList) {
        logger.info("Handling a Http GET Admin request");
        String response;
        if(storeList == null || storeList.isEmpty()) {
            response = storeClientConfigs.getAllConfigs();
        } else {
            response = storeClientConfigs.getSpecificConfigs(storeList);
        }
        HttpResponseStatus responseStatus;
        if(response.contains(StoreClientConfigService.ERROR_MESSAGE_PARAM_KEY)
           && response.contains(StoreClientConfigService.STORE_NOT_FOUND_ERROR)) {
            responseStatus = NOT_FOUND;
        } else {
            responseStatus = OK;
        }
        return sendResponse(responseStatus, response);
    }

    private HttpResponse handlePut(Map<String, Properties> configsToPut) {
        logger.info("Handling a Http POST Admin request");
        String response = storeClientConfigs.putConfigs(configsToPut);
        HttpResponseStatus responseStatus;
        if(response.contains(StoreClientConfigService.ERROR_MESSAGE_PARAM_KEY)) {
            responseStatus = BAD_REQUEST;
        } else {
            responseStatus = OK;
        }
        return sendResponse(responseStatus, response);
    }

    private HttpResponse handleDelete(List<String> storeList) {
        logger.info("Handling a Http DELETE Admin request");
        String response = storeClientConfigs.deleteSpecificConfigs(storeList);
        HttpResponseStatus responseStatus;
        if(response.contains(StoreClientConfigService.ERROR_MESSAGE_PARAM_KEY)
           && response.contains(StoreClientConfigService.STORE_ALREADY_DOES_NOT_EXIST_WARNING)) {
            responseStatus = NOT_FOUND;
        } else {
            responseStatus = OK;
        }
        return sendResponse(responseStatus, response);
    }

    private HttpResponse handleBadRequest(String errorCause) {
        String errorMessage = "Handling a Bad Http Admin request received: " + errorCause;
        logger.error(errorMessage);
        return sendResponse(BAD_REQUEST, errorMessage);
    }

    public HttpResponse sendResponse(HttpResponseStatus responseCode, String responseBody) {
        String actualResponseBody = responseBody + "\n";
        HttpResponse response = new DefaultHttpResponse(HTTP_1_1, responseCode);
        response.setHeader(CONTENT_LENGTH, actualResponseBody.length());
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        try {
            outputStream.write(actualResponseBody.getBytes());
        } catch(IOException e) {
            logger.error("IOException while trying to write the outputStream for an admin response", e);
            throw new RuntimeException(e);
        }
        ChannelBuffer responseContent = ChannelBuffers.dynamicBuffer();
        responseContent.writeBytes(outputStream.toByteArray());
        response.setContent(responseContent);
        if (logger.isDebugEnabled()) {
            logger.debug("Sent " + response);
        }
        return response;
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
        e.getCause().printStackTrace();
        e.getChannel().close();
    }
}
TOP

Related Classes of voldemort.rest.coordinator.admin.CoordinatorAdminRequestHandler

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.