view common/mongodb/src/main/java/com/redhat/thermostat/gateway/common/mongodb/servlet/MongoHttpHandlerHelper.java @ 281:fdd31cc5e164

Make Auth implementation more generic and improve structure of code Reviewed-by: jkang Review-thread: http://icedtea.classpath.org/pipermail/thermostat/2017-October/025347.html
author Miloslav Zezulka <mzezulka@redhat.com>
date Tue, 17 Oct 2017 11:11:23 +0200
parents 3055303a670f
children
line wrap: on
line source

/*
 * Copyright 2012-2017 Red Hat, Inc.
 *
 * This file is part of Thermostat.
 *
 * Thermostat is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published
 * by the Free Software Foundation; either version 2, or (at your
 * option) any later version.
 *
 * Thermostat is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Thermostat; see the file COPYING.  If not see
 * <http://www.gnu.org/licenses/>.
 *
 * Linking this code with other modules is making a combined work
 * based on this code.  Thus, the terms and conditions of the GNU
 * General Public License cover the whole combination.
 *
 * As a special exception, the copyright holders of this code give
 * you permission to link this code with independent modules to
 * produce an executable, regardless of the license terms of these
 * independent modules, and to copy and distribute the resulting
 * executable under terms of your choice, provided that you also
 * meet, for each linked independent module, the terms and conditions
 * of the license of that module.  An independent module is a module
 * which is not derived from or based on this code.  If you modify
 * this code, you may extend this exception to your version of the
 * library, but you are not obligated to do so.  If you do not wish
 * to do so, delete this exception statement from your version.
 */

package com.redhat.thermostat.gateway.common.mongodb.servlet;

import static com.redhat.thermostat.gateway.common.util.ServiceException.DATABASE_UNAVAILABLE;
import static com.redhat.thermostat.gateway.common.util.ServiceException.MALFORMED_CLIENT_REQUEST;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.core.Response;

import org.bson.json.JsonParseException;

import com.mongodb.DBObject;
import com.mongodb.MongoTimeoutException;
import com.mongodb.MongoWriteException;
import com.redhat.thermostat.gateway.common.core.auth.RealmAuthorizer;
import com.redhat.thermostat.gateway.common.core.servlet.CommonQueryParams;
import com.redhat.thermostat.gateway.common.db.Pair;
import com.redhat.thermostat.gateway.common.db.servlet.AbstractHttpHandlerHelper;
import com.redhat.thermostat.gateway.common.mongodb.ThermostatFields;
import com.redhat.thermostat.gateway.common.mongodb.ThermostatMongoStorage;
import com.redhat.thermostat.gateway.common.mongodb.executor.MongoDataResultContainer;
import com.redhat.thermostat.gateway.common.mongodb.executor.MongoExecutor;
import com.redhat.thermostat.gateway.common.mongodb.response.MongoMetaDataGenerator;
import com.redhat.thermostat.gateway.common.mongodb.response.MongoMetaDataResponseBuilder;
import com.redhat.thermostat.gateway.common.mongodb.response.MongoResponseBuilder;
import com.redhat.thermostat.gateway.common.util.ServiceException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class MongoHttpHandlerHelper extends AbstractHttpHandlerHelper {

    private final MongoExecutor mongoExecutor = new MongoExecutor();

    public MongoHttpHandlerHelper(String collectionName) {
        super(collectionName);
    }

    @Override
    protected List<Pair<Class<? extends Exception>, ServiceException>> getImplSpecificHandlers() {
        List<Pair<Class<? extends Exception>, ServiceException>> result = new ArrayList<>();

        result.add(new Pair<Class<? extends Exception>, ServiceException>(MongoWriteException.class, MALFORMED_CLIENT_REQUEST));
        result.add(new Pair<Class<? extends Exception>, ServiceException>(JsonParseException.class, MALFORMED_CLIENT_REQUEST));
        result.add(new Pair<Class<? extends Exception>, ServiceException>(MongoTimeoutException.class, DATABASE_UNAVAILABLE));
        return result;
    }

    /*
     * originalQueries contains only query info from the client's original request argument. queries contains this info,
     * as well as added JVM/SYS ids built by andSystemIdJvmIdQuery(...).
     */
    @Override
    public Response handleGetImpl(RealmAuthorizer realmAuthorizer, HttpServletRequest httpServletRequest,
            ServletContext context, String queries, CommonQueryParams params) throws Exception {
        if (realmAuthorizer.readable()) {
            ThermostatMongoStorage storage = (ThermostatMongoStorage) context.getAttribute(ServletContextConstants.MONGODB_CLIENT_ATTRIBUTE);

            MongoDataResultContainer execResult = mongoExecutor.execGetRequest(
                    storage.getDatabase().getCollection(getCollectionName()), queries, params, realmAuthorizer.getReadableRealms());

            MongoResponseBuilder.Builder responseBuilder = new MongoResponseBuilder.Builder();
            responseBuilder.addQueryDocuments(execResult.getQueryDataResult());

            if (params.isReturnMetadata()) {

                Map<String, String> paramArgs = params.buildParams();

                String baseUrl = httpServletRequest.getRequestURL().toString();
                MongoMetaDataResponseBuilder.MetaBuilder metaDataResponse = new MongoMetaDataResponseBuilder.MetaBuilder();
                MongoMetaDataGenerator metaDataGenerator = new MongoMetaDataGenerator(params, paramArgs, execResult, baseUrl);

                metaDataGenerator.setDocAndPayloadCount(metaDataResponse);
                metaDataGenerator.setPrev(metaDataResponse);
                metaDataGenerator.setNext(metaDataResponse);

                responseBuilder.addMetaData(metaDataResponse.build());
            }
            return okResponse(responseBuilder);
        } else {
            return errorResponse();
        }
    }

    @Override
    public Response handlePutImpl(RealmAuthorizer realmAuthorizer, ServletContext context,
            String systemId, String jvmId, String queries, boolean returnMetadata, String body) throws Exception {
        if (realmAuthorizer.updatable()) {
            ThermostatMongoStorage storage = (ThermostatMongoStorage) context.getAttribute(ServletContextConstants.MONGODB_CLIENT_ATTRIBUTE);

            MongoDataResultContainer execResult = mongoExecutor.execPutRequest(storage.getDatabase().getCollection(getCollectionName()), body, queries, realmAuthorizer.getUpdatableRealms(), systemId, jvmId);

            MongoResponseBuilder.Builder responseBuilder = new MongoResponseBuilder.Builder();
            if (returnMetadata) {
                MongoMetaDataResponseBuilder.MetaBuilder metadataResponse = new MongoMetaDataResponseBuilder.MetaBuilder();
                metadataResponse.matchCount(execResult.getPutReqMatches());

                responseBuilder.addMetaData(metadataResponse.build());
            }

            return okResponse(responseBuilder);
        } else {
            return errorResponse();
        }
    }

    @Override
    public Response handlePostImpl(RealmAuthorizer realmAuthorizer, ServletContext context,
            String systemId, String jvmId, boolean returnMetadata, String body) throws Exception {
        if (realmAuthorizer.writable()) {
            ThermostatMongoStorage storage = (ThermostatMongoStorage) context.getAttribute(ServletContextConstants.MONGODB_CLIENT_ATTRIBUTE);

            MongoDataResultContainer execResult = mongoExecutor.execPostRequest(storage.getDatabase().getCollection(getCollectionName(), DBObject.class), body, realmAuthorizer.getWritableRealms(), systemId, jvmId);
            MongoResponseBuilder.Builder responseBuilder = new MongoResponseBuilder.Builder();

            if (returnMetadata) {
                MongoMetaDataResponseBuilder.MetaBuilder metadataResponse = new MongoMetaDataResponseBuilder.MetaBuilder();
                metadataResponse.insertCount(execResult.getPostReqInsertions());

                responseBuilder.addMetaData(metadataResponse.build());
            }

            return okResponse(responseBuilder);
        } else {
            return errorResponse();
        }
    }

    @Override
    public Response handleDeleteImpl(RealmAuthorizer realmAuthorizer, ServletContext context,
            String queries, boolean returnMetadata) throws Exception {
        if (realmAuthorizer.deletable()) {
            ThermostatMongoStorage storage = (ThermostatMongoStorage) context.getAttribute(ServletContextConstants.MONGODB_CLIENT_ATTRIBUTE);

            MongoDataResultContainer execResult = mongoExecutor.execDeleteRequest(storage.getDatabase().getCollection(getCollectionName()), queries, realmAuthorizer.getDeletableRealms());

            MongoResponseBuilder.Builder responseBuilder = new MongoResponseBuilder.Builder();
            if (returnMetadata) {
                MongoMetaDataResponseBuilder.MetaBuilder metadataResponse = new MongoMetaDataResponseBuilder.MetaBuilder();
                metadataResponse.matchCount(execResult.getDeleteReqMatches());

                responseBuilder.addMetaData(metadataResponse.build());
            }

            return okResponse(responseBuilder);
        } else {
            return errorResponse();
        }
    }

    /*
     * Utility code
     */
    @Override
    protected String andSystemIdQuery(final String originalQuery, final String systemId) {
        final String sysQuery = ThermostatFields.SYSTEM_ID + "==\"" + systemId + '"';
        return isNullOrEmpty(originalQuery) ? sysQuery : sysQuery + ',' + originalQuery;
    }

    @Override
    protected String andSystemIdJvmIdQuery(final String originalQuery, final String systemId, final String jvmId) {
        final String jvmQuery = ThermostatFields.JVM_ID + "==\"" + jvmId + '"';
        final String sysJvmQuery = jvmQuery + (isNullOrEmpty(systemId) ? "" : ',' + ThermostatFields.SYSTEM_ID + "==\"" + systemId + '"');
        return isNullOrEmpty(originalQuery) ? sysJvmQuery : sysJvmQuery + ',' + originalQuery;
    }

    private Response errorResponse() {
        return Response.status(Response.Status.FORBIDDEN).build();
    }

    private Response okResponse(MongoResponseBuilder.Builder responseBuilder) {
        return Response.status(Response.Status.OK).entity(responseBuilder.build()).build();
    }
}