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

com.eightkdata.mongowp.server.api.impl.MapBasedCommandsExecutor Maven / Gradle / Ivy

There is a newer version: 0.50.0
Show newest version
/*
 *     This file is part of mongowp.
 *
 *     mongowp is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Affero General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 *
 *     mongowp 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 Affero General Public License for more details.
 *
 *     You should have received a copy of the GNU Affero General Public License
 *     along with mongowp. If not, see .
 *
 *     Copyright (c) 2014, 8Kdata Technology
 *     
 */
package com.eightkdata.mongowp.server.api.impl;

import com.eightkdata.mongowp.server.api.CommandImplementation;
import com.eightkdata.mongowp.server.api.CommandResult;
import com.eightkdata.mongowp.server.api.CommandReply;
import com.eightkdata.mongowp.server.api.CommandsExecutor;
import com.eightkdata.mongowp.server.api.CommandsLibrary;
import com.eightkdata.mongowp.server.api.Command;
import com.eightkdata.mongowp.server.api.CommandRequest;
import com.eightkdata.mongowp.exceptions.CommandNotSupportedException;
import com.eightkdata.mongowp.exceptions.MongoException;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 */
@SuppressWarnings("unchecked")
public class MapBasedCommandsExecutor implements CommandsExecutor {
    private static final Logger LOGGER
            = LoggerFactory.getLogger(MapBasedCommandsExecutor.class);

    /**
     * A map that associates each command with its implementation.
     * 
     * It is guaranteed by construction that the implementation uses the same
     * request and reply than command it is associated with.
     */
    private final ImmutableMap implementations;

    private MapBasedCommandsExecutor(ImmutableMap implementations) {
        this.implementations = implementations;
    }
    
    @Override
    public  CommandReply execute(
            @Nonnull Command command,
            @Nonnull CommandRequest request)
            throws MongoException, CommandNotSupportedException {
        CommandImplementation implementation = implementations.get(command);
        if (implementation == null) {
            throw new CommandNotSupportedException(command.getCommandName());
        }
        try {
            CommandResult result = implementation.apply(command, request);
            if (command.isReadyToReplyResult(result.getResult())) {
                return new DelegateCommandReply<>(command, result);
            }
            else {
                return new CorrectCommandReply<>(command, result);
            }
        } catch (MongoException ex) {
            return new FailedCommandReply<>(ex);
        }
    }
    
    
    public static Builder fromLibraryBuilder(CommandsLibrary library) {
        return new FromLibraryBuilder(library);
    }

    public static Builder builder() {
        return new UnsafeBuilder();
    }
    
    public static interface Builder {
        
        public  Builder addImplementation(
                @Nonnull Command command,
                @Nonnull CommandImplementation implementation);

        public  Builder addImplementations(
                Iterable, CommandImplementation>> entries);
        
        public MapBasedCommandsExecutor build();
    }

    private static class UnsafeBuilder implements Builder {

        private final Map implementations = Maps.newHashMap();

        @Override
        public  Builder addImplementations(
                Iterable, CommandImplementation>> entries) {
            for (Entry, CommandImplementation> entry : entries) {
                addImplementation(entry.getKey(), entry.getValue());
            }
            return this;
        }

        @Override
        public  Builder addImplementation(
                Command command,
                CommandImplementation implementation) {
            if (implementations.containsKey(command)) {
                throw new IllegalArgumentException(
                        "There is another implementation ("
                        + implementations.get(command) + " associated to "
                        + command);
            }

            implementations.put(command, implementation);

            return this;
        }

        @Override
        public MapBasedCommandsExecutor build() {
            return new MapBasedCommandsExecutor(
                    ImmutableMap.copyOf(implementations)
            );
        }
    }
    
    private static class FromLibraryBuilder extends UnsafeBuilder {
        private final @Nullable Set notImplementedCommands;

        public FromLibraryBuilder(CommandsLibrary library) {
            this.notImplementedCommands = library.getSupportedCommands();
            if (this.notImplementedCommands == null) {
                LOGGER.warn("An unsafe commands library has been used to "
                        + "create an executor. It is impossible to check at "
                        + "creation time if all commands supported by the "
                        + "library have an associated implementation");
            }
        }

        @Override
        public  Builder addImplementations(
                Iterable, CommandImplementation>> entries) {
            for (Entry, CommandImplementation> entry : entries) {
                addImplementation(entry.getKey(), entry.getValue());
            }
            return this;
        }
        
        @Override
        public  Builder addImplementation(
                Command command,
                CommandImplementation implementation) {
            if (notImplementedCommands != null && !notImplementedCommands.remove(command)) {
                throw new IllegalArgumentException("Command " + command + " is "
                        + "not supported by the given library");
            }
            return super.addImplementation(command, implementation);
        }
        
        @Override
        public MapBasedCommandsExecutor build() {
            if (notImplementedCommands != null) {
                Preconditions.checkState(
                        notImplementedCommands.isEmpty(),
                        "The following commands have no implementation: %s",
                        notImplementedCommands
                );
            }
            return super.build();
        }
    }
    
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy