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

io.github.jiashunx.masker.rest.framework.MRestServer Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
package io.github.jiashunx.masker.rest.framework;

import io.github.jiashunx.masker.rest.framework.cons.Constants;
import io.github.jiashunx.masker.rest.framework.exception.MRestServerInitializeException;
import io.github.jiashunx.masker.rest.framework.filter.MRestFilter;
import io.github.jiashunx.masker.rest.framework.filter.MRestFilterChain;
import io.github.jiashunx.masker.rest.framework.filter.MRestDispatchFilter;
import io.github.jiashunx.masker.rest.framework.handler.*;
import io.github.jiashunx.masker.rest.framework.util.MRestHeaderBuilder;
import io.github.jiashunx.masker.rest.framework.util.MRestUtils;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;

/**
 * @author jiashunx
 */
public class MRestServer {

    private static final Logger logger = LoggerFactory.getLogger(MRestServer.class);

    private volatile boolean started = false;

    private final int port;
    private final String serverName;

    public MRestServer() {
        this(MRestUtils.getDefaultServerPort(), MRestUtils.getDefaultServerName());
    }

    public MRestServer(String serverName) {
        this(MRestUtils.getDefaultServerPort(), serverName);
    }

    public MRestServer(int port) {
        this(port, MRestUtils.getDefaultServerName());
    }

    public MRestServer(int port, String serverName) {
        if (port <= 0 || port > 65535 || StringUtils.isBlank(serverName)) {
            throw new MRestServerInitializeException("illegal arguments");
        }
        this.port = port;
        this.serverName = serverName;
    }

    /**
     * 检查server是否已启动
     * @throws MRestServerInitializeException MRestServerInitializeException
     */
    private void checkServerState() throws MRestServerInitializeException {
        if (started) {
            throw new MRestServerInitializeException(String.format("server: %s has already been initialized", serverName));
        }
    }

    /**
     * 启动server
     * @throws MRestServerInitializeException MRestServerInitializeException
     */
    public synchronized void start() throws MRestServerInitializeException {
        checkServerState();
        if (logger.isInfoEnabled()) {
            logger.info("start server: {}, listening on port: {}", serverName, port);
        }
        try {
            EventLoopGroup bossGroup = new NioEventLoopGroup();
            EventLoopGroup workerGroup = new NioEventLoopGroup();
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
            bootstrap.option(ChannelOption.TCP_NODELAY, true);
            bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    .childHandler(new MRestServerChannelInitializer(this));
            Channel channel = bootstrap.bind(port).sync().channel();
            if (logger.isInfoEnabled()) {
                logger.info("start server: {} success.", serverName);
            }
            final Thread syncThread = new Thread(() -> {
                try {
                    channel.closeFuture().syncUninterruptibly();
                } catch (Throwable throwable) {
                    if (logger.isErrorEnabled()) {
                        logger.error("server: {} channel close future synchronized failed", serverName, throwable);
                    }
                }
            });
            syncThread.setName(serverName);
            syncThread.setDaemon(true);
            syncThread.start();
            started = true;
        } catch (Throwable throwable) {
            throw new MRestServerInitializeException(String.format("start server: %s failed", serverName), throwable);
        }
    }


    /**************************************************** SEP ****************************************************/
    /**************************************************** SEP ****************************************************/


    /**
     * 输入MRestRequest, 返回自定义对象.
     */
    private final Map> functionHandlerMap = new HashMap<>();
    /**
     * 输入MRestRequest, 无返回.
     */
    private final Map> consumerHandlerMap1 = new HashMap<>();
    /**
     * 输入MRestRequest, MRestResponse, 无返回.
     */
    private final Map> consumerHandlerMap2 = new HashMap<>();

    private static final Set MAPPING_URL_SET = new HashSet<>();

    /**
     * 指定url是否是已指定映射处理.
     * @param requestURL requestURL
     * @return boolean
     */
    public boolean isMappingURL(String requestURL) {
        return MAPPING_URL_SET.contains(requestURL);
    }

    /**
     * 检查映射url正确性.
     * @param url url
     */
    private void checkMappingUrl(String url) {
        if (StringUtils.isBlank(url)) {
            throw new IllegalArgumentException(String.format("illegal mapping url: %s", url));
        }
        if (isMappingURL(url)) {
            throw new MRestServerInitializeException(String.format("url mapping conflict: %s", url));
        }
    }

    public synchronized MRestServer mapping(String url, Consumer handler, HttpMethod... methods) {
        return mapping(url, handler, MRestHeaderBuilder.Build(), methods);
    }

    public synchronized MRestServer mapping(String url, Consumer handler, Map headers, HttpMethod... methods) {
        return mapping(url, handler, MRestHandlerConfig.newInstance(headers), methods);
    }

    public synchronized MRestServer mapping(String url, Consumer handler, MRestHandlerConfig config, HttpMethod... methods) {
        checkServerState();
        checkMappingUrl(url);
        MRestHandler1 restHandler = new MRestHandler1<>(url, handler, config, methods);
        consumerHandlerMap1.put(url, restHandler);
        MAPPING_URL_SET.add(url);
        if (logger.isInfoEnabled()) {
            logger.info("server: {} register url {} handler success, method: {}", serverName, url, methods);
        }
        return this;
    }

    public synchronized MRestServer mapping(String url, BiConsumer handler, HttpMethod... methods) {
        return mapping(url, handler, MRestHeaderBuilder.Build(), methods);
    }

    public synchronized MRestServer mapping(String url, BiConsumer handler, Map headers, HttpMethod... methods) {
        return mapping(url, handler, MRestHandlerConfig.newInstance(headers), methods);
    }

    public synchronized MRestServer mapping(String url, BiConsumer handler, MRestHandlerConfig config, HttpMethod... methods) {
        checkServerState();
        checkMappingUrl(url);
        MRestHandler2 restHandler = new MRestHandler2<>(url, handler, config, methods);
        consumerHandlerMap2.put(url, restHandler);
        MAPPING_URL_SET.add(url);
        if (logger.isInfoEnabled()) {
            logger.info("server: {} register url {} handler success, method: {}", serverName, url, methods);
        }
        return this;
    }

    public synchronized  MRestServer mapping(String url, Function handler, HttpMethod... methods) {
        return mapping(url, handler, MRestHeaderBuilder.Build(), methods);
    }

    public synchronized  MRestServer mapping(String url, Function handler, Map headers, HttpMethod... methods) {
        return mapping(url, handler, MRestHandlerConfig.newInstance(headers), methods);
    }

    public synchronized  MRestServer mapping(String url, Function handler, MRestHandlerConfig config, HttpMethod... methods) {
        checkServerState();
        checkMappingUrl(url);
        MRestHandler0 restHandler = new MRestHandler0<>(url, handler, config, methods);
        functionHandlerMap.put(url, restHandler);
        MAPPING_URL_SET.add(url);
        if (logger.isInfoEnabled()) {
            logger.info("server: {} register url {} handler success, method: {}", serverName, url, methods);
        }
        return this;
    }

    public MRestServer get(String url, Consumer handler) {
        return mapping(url, handler, HttpMethod.GET);
    }

    public MRestServer get(String url, Consumer handler, Map headers) {
        return mapping(url, handler, headers, HttpMethod.GET);
    }

    public MRestServer get(String url, Consumer handler, MRestHandlerConfig config) {
        return mapping(url, handler, config, HttpMethod.GET);
    }

    public  MRestServer get(String url, Function handler) {
        return mapping(url, handler, HttpMethod.GET);
    }

    public  MRestServer get(String url, Function handler, Map headers) {
        return mapping(url, handler, headers, HttpMethod.GET);
    }

    public  MRestServer get(String url, Function handler, MRestHandlerConfig config) {
        return mapping(url, handler, config, HttpMethod.GET);
    }

    public MRestServer get(String url, BiConsumer handler) {
        return mapping(url, handler, HttpMethod.GET);
    }

    public MRestServer get(String url, BiConsumer handler, Map headers) {
        return mapping(url, handler, headers, HttpMethod.GET);
    }

    public MRestServer get(String url, BiConsumer handler, MRestHandlerConfig config) {
        return mapping(url, handler, config, HttpMethod.GET);
    }

    public MRestServer post(String url, Consumer handler) {
        return mapping(url, handler, HttpMethod.POST);
    }

    public MRestServer post(String url, Consumer handler, Map headers) {
        return mapping(url, handler, headers, HttpMethod.POST);
    }

    public MRestServer post(String url, Consumer handler, MRestHandlerConfig config) {
        return mapping(url, handler, config, HttpMethod.POST);
    }

    public  MRestServer post(String url, Function handler) {
        return mapping(url, handler, HttpMethod.POST);
    }

    public  MRestServer post(String url, Function handler, Map headers) {
        return mapping(url, handler, headers, HttpMethod.POST);
    }

    public  MRestServer post(String url, Function handler, MRestHandlerConfig config) {
        return mapping(url, handler, config, HttpMethod.POST);
    }

    public MRestServer post(String url, BiConsumer handler) {
        return mapping(url, handler, HttpMethod.POST);
    }

    public MRestServer post(String url, BiConsumer handler, Map headers) {
        return mapping(url, handler, headers, HttpMethod.POST);
    }

    public MRestServer post(String url, BiConsumer handler, MRestHandlerConfig config) {
        return mapping(url, handler, config, HttpMethod.POST);
    }

    public MRestHandler1 getConsumerHandler1(String requestURL) {
        return consumerHandlerMap1.get(requestURL);
    }

    public MRestHandler2 getConsumerHandler2(String requestURL) {
        return consumerHandlerMap2.get(requestURL);
    }

    public MRestHandler0 getFunctionHandler(String requestURL) {
        return functionHandlerMap.get(requestURL);
    }


    /**************************************************** SEP ****************************************************/
    /**************************************************** SEP ****************************************************/


    /**
     * filter映射处理.
     */
    private final Map> filterMap = new HashMap<>();

    private final MRestFilter requestFilter = new MRestDispatchFilter();

    public MRestFilterChain getFilterChain(String requestURL) {
        Set filterSet = new HashSet<>();
        filterMap.forEach((urlPattern, filterList) -> {
            String pattern = "^" + urlPattern.replace("*", "\\S*") + "$";
            if (requestURL.matches(pattern)) {
                filterSet.addAll(filterList);
            }
        });
        // 对filter进行排序, 按照order小到大进行顺序排序.
        LinkedList filterList = new LinkedList<>(filterSet);
        filterList.sort((filter0, filter1) -> {
            int order0 = filter0.order();
            int order1 = filter1.order();
            return order1 - order0;
        });
        filterList.addLast(requestFilter);
        return new MRestFilterChain(this, filterList.toArray(new MRestFilter[0]));
    }

    /**
     * 添加filter, 自动扫描filter注解, 获取urlPattern.
     * @param filterArr filterArr
     * @return MRestServer
     */
    public synchronized MRestServer filter(MRestFilter... filterArr) {
        for (MRestFilter filter: filterArr) {
            String[] urlPatterns = filter.urlPatterns();
            if (urlPatterns == null || urlPatterns.length == 0) {
                urlPatterns = Constants.DEFAULT_FILTER_URLPATTERNS;
            }
            filter0(filter, urlPatterns);
        }
        return this;
    }

    /**
     * 添加filter, 如果filter未配置注解, 则根据传入urlPattern来进行匹配, 否则将注解指定的urlPattern和urlPattern参数进行合并.
     * @param urlPattern urlPattern
     * @param filterArr filterArr
     * @return MRestServer
     */
    public synchronized MRestServer filter(String urlPattern, MRestFilter... filterArr) {
        for (MRestFilter filter: filterArr) {
            Set urlPatterns = new HashSet<>(Arrays.asList(filter.urlPatterns()));
            if (!filter.hasFilterAnnotation()) {
                urlPatterns.clear();
            }
            urlPatterns.add(urlPattern);
            filter0(filter, urlPatterns.toArray(new String[0]));
        }
        return this;
    }

    private synchronized void filter0(MRestFilter filter, String... urlPatterns) {
        checkServerState();
        if (filter == null || urlPatterns.length == 0) {
            throw new IllegalArgumentException();
        }
        for (String urlPattern: urlPatterns) {
            filterMap.computeIfAbsent(urlPattern, k -> new ArrayList<>()).add(filter);
        }
    }


    /**************************************************** SEP ****************************************************/
    /**************************************************** SEP ****************************************************/

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy