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

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

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

import com.fasterxml.jackson.databind.ObjectMapper;
import io.github.jiashunx.masker.rest.framework.cons.Constants;
import io.github.jiashunx.masker.rest.framework.exception.MRestMappingException;
import io.github.jiashunx.masker.rest.framework.exception.MRestServerInitializeException;
import io.github.jiashunx.masker.rest.framework.model.*;
import io.github.jiashunx.masker.rest.framework.servlet.AbstractRestServlet;
import io.github.jiashunx.masker.rest.framework.servlet.MRestDispatchServlet;
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.StaticResourceFilter;
import io.github.jiashunx.masker.rest.framework.function.VoidFunc;
import io.github.jiashunx.masker.rest.framework.handler.*;
import io.github.jiashunx.masker.rest.framework.servlet.MRestServlet;
import io.github.jiashunx.masker.rest.framework.servlet.MRestServletAdapter;
import io.github.jiashunx.masker.rest.framework.util.*;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.HttpResponseStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.*;
import java.util.stream.Collectors;

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

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

    private final MRestServer restServer;
    private final String contextPath;
    private final StaticResourceHolder staticResourceHolder;
    private final Map websocketContextMap = new ConcurrentHashMap<>();

    public MRestContext(MRestServer restServer, String contextPath) {
        this.restServer = Objects.requireNonNull(restServer);
        this.contextPath = MRestUtils.formatContextPath(contextPath);
        // websocket-context初始化
        websocketContextMap.put(Constants.DEFAULT_WEBSOCKET_CONTEXT_PATH, new MWebsocketContext(this.restServer, this, Constants.DEFAULT_WEBSOCKET_CONTEXT_PATH));
        // 添加框架提供的静态资源
        addClasspathResources("/masker-rest/static", new String[]{ "masker-rest/static/" });
        this.staticResourceHolder = new StaticResourceHolder(this);
    }

    public MRestServer getRestServer() {
        return restServer;
    }
    public String getContextPath() {
        return contextPath;
    }

    public String getContextDesc() {
        return String.format("%s Context[%s]", getRestServer().getServerDesc(), getContextPath());
    }

    public StaticResourceHolder getStaticResourceHolder() {
        return staticResourceHolder;
    }

    void init() {
        // websocket-context初始化
        websocketContextMap.forEach((key, websocketContext) -> {
            websocketContext.init();
        });

        // mapping处理
        for (VoidFunc mappingTask: mappingTaskList) {
            mappingTask.doSomething();
        }
        // servlet处理
        for (VoidFunc servletTask: servletTaskList) {
            servletTask.doSomething();
        }
        // filter处理
        for (VoidFunc filterTask: filterTaskList) {
            filterTask.doSomething();
        }
        // 静态资源处理
        reloadResource();
        if (isAutoRefreshStaticResources()) {
            new Thread(() -> {
                while (true) {
                    try {
                        Thread.sleep(getAutoRefreshStaticResourcesPeriod());
                        reloadResource();
                    } catch (Throwable throwable) {
                        if (logger.isErrorEnabled()) {
                            logger.error("reload static resource failed.", throwable);
                        }
                    }
                }
            }, "ResourceReload" + restServer.getListenPort() + "_" + getContextPath()).start();
        }
    }

    private void reloadResource() {
        Map> classpathResources = getClasspathResources();
        if (logger.isInfoEnabled()) {
            logger.info("{} reload classpath resources: {}", getContextDesc(), classpathResources);
        }
        Map> diskResources = getDiskResources();
        if (logger.isInfoEnabled()) {
            logger.info("{} reload disk resources: {}", getContextDesc(), diskResources);
        }
        staticResourceHolder.reloadResourceMap(classpathResources, diskResources);
    }

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

    private final Map> urlMappingHandler = new HashMap<>();

    /**
     * 添加url映射处理的任务(在服务启动时统一添加).
     */
    private final List mappingTaskList = new ArrayList<>();

    /**
     * 指定url是否是已指定映射处理.
     * @param requestURL requestURL
     * @param methods methods
     * @return boolean
     */
    public boolean isMappingURL(String requestURL, HttpMethod... methods) {
        if (urlMappingHandler.containsKey(requestURL)) {
            Map handlerMap = urlMappingHandler.get(requestURL);
            for (HttpMethod method: methods) {
                if (handlerMap.get(method) != null) {
                    return true;
                }
            }
        }
        return false;
    }

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

    private void checkMappingHandler(MRestHandler handler) {
        if (handler == null || handler.getHandler() == null) {
            throw new NullPointerException(String.format("%s mapping handler cann't be null", getContextDesc()));
        }
    }

    public MRestContext mapping(String url, Supplier handler, HttpMethod... methods) {
        return mapping(url, handler, MRestHeaderBuilder.Build(), methods);
    }

    public MRestContext mapping(String url, Supplier handler, Map headers, HttpMethod... methods) {
        return mapping(url, handler, MRestHandlerConfig.newInstance(headers), methods);
    }

    public MRestContext mapping(String url, Supplier handler, MRestHandlerConfig config, HttpMethod... methods) {
        return mapping(url, new MRestHandlerSupplier<>(url, handler, config, methods), methods);
    }

    public MRestContext mapping(String url, VoidFunc handler, HttpMethod... methods) {
        return mapping(url, handler, MRestHeaderBuilder.Build(), methods);
    }

    public MRestContext mapping(String url, VoidFunc handler, Map headers, HttpMethod... methods) {
        return mapping(url, handler, MRestHandlerConfig.newInstance(headers), methods);
    }

    public MRestContext mapping(String url, VoidFunc handler, MRestHandlerConfig config, HttpMethod... methods) {
        return mapping(url, new MRestHandlerConsumerVoid(url, handler, config, methods), methods);
    }

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

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

    public MRestContext mapping(String url, Consumer handler, MRestHandlerConfig config, HttpMethod... methods) {
        return mapping(url, new MRestHandlerConsumerReq<>(url, handler, config, methods), methods);
    }

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

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

    public MRestContext mapping(String url, BiConsumer handler, MRestHandlerConfig config, HttpMethod... methods) {
        return mapping(url, new MRestHandlerConsumerReqResp<>(url, handler, config, methods), methods);
    }

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

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

    public  MRestContext mapping(String url, Function handler, MRestHandlerConfig config, HttpMethod... methods) {
        return mapping(url, new MRestHandlerFunction<>(url, handler, config, methods), methods);
    }

    public  MRestContext mapping(String url, BiFunction handler, HttpMethod... methods) {
        return mapping(url, handler, MRestHeaderBuilder.Build(), methods);
    }

    public  MRestContext mapping(String url, BiFunction handler, Map headers, HttpMethod... methods) {
        return mapping(url, handler, MRestHandlerConfig.newInstance(headers), methods);
    }

    public  MRestContext mapping(String url, BiFunction handler, MRestHandlerConfig config, HttpMethod... methods) {
        return mapping(url, new MRestHandlerBiFunction<>(url, handler, config, methods), methods);
    }

    private synchronized MRestContext mapping(String url, MRestHandler handler, HttpMethod... methods) {
        getRestServer().checkServerState();
        mappingTaskList.add(() -> {
            checkMappingUrl(url, methods);
            checkMappingHandler(handler);
            Map handlerMap = urlMappingHandler.computeIfAbsent(url, k -> new HashMap<>());
            for (HttpMethod method: methods) {
                handlerMap.put(method, handler);
            }
            if (logger.isInfoEnabled()) {
                logger.info("{} register url handler success, {}, {}", getContextDesc(), methods, url);
            }
        });
        return this;
    }

    public MRestHandler getUrlMappingHandler(String requestURL, HttpMethod method) {
        Map handlerMap = urlMappingHandler.get(requestURL);
        if (handlerMap != null) {
            return handlerMap.get(method);
        }
        return null;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    public MRestContext fileupload(String url, Consumer handler) {
        return post(url, handler);
    }

    public  MRestContext fileupload(String url, Function handler) {
        return post(url, handler);
    }

    public  MRestContext fileupload(String url, BiFunction handler) {
        return post(url, handler);
    }

    public MRestContext fileupload(String url, BiConsumer handler) {
        return post(url, handler);
    }

    public MRestContext filedownload(String url, BiConsumer handler) {
        return get(url, handler);
    }


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


    /**
     * servlet映射处理.
     */
    private final Map servletMap = new LinkedHashMap<>();
    /**
     * filter映射处理.
     */
    private final Map> filterMap = new HashMap<>();
    /**
     * 请求分发处理.
     */
    private final MRestServlet dispatchServlet = new MRestDispatchServlet();
    /**
     * 配置的静态资源classpath扫描路径.
     */
    private final Map> classpathResources = new HashMap<>();
    /**
     * 配置的静态资源磁盘扫描路径.
     */
    private final Map> diskResources = new HashMap<>();
    /**
     * 静态资源处理.
     */
    private final MRestFilter staticResourceFilter = new StaticResourceFilter(this);
    /**
     * 添加servlet的任务(在服务启动时统一添加).
     */
    private final List servletTaskList = new ArrayList<>();
    /**
     * 添加filter的任务(在服务启动时统一添加).
     */
    private final List filterTaskList = new ArrayList<>();

    public MRestFilterChain getCommonStaticResourceFilterChain(String requestURL) {
        List filterList = new LinkedList<>();
        filterList.add(staticResourceFilter);
        filterList.add((request, response, filterChain) -> {
            dispatchServlet.service(request, response);
        });
        return new MRestFilterChain(this, filterList.toArray(new MRestFilter[0]));
    }

    public MRestServlet getServlet(String requestURL) {
        List mappingServletList = new ArrayList<>();
        // 扩展名匹配
        AtomicReference extRef = new AtomicReference<>();
        // 路径匹配
        AtomicReference pathMatchRef = new AtomicReference<>();
        // 精确匹配 - 带占位符
        AtomicReference strictlyRef0 = new AtomicReference<>();
        // 精确匹配 - 不带占位符
        AtomicReference strictlyRef1 = new AtomicReference<>();
        servletMap.forEach((_up, urlMappingServlet) -> {
            UrlMatchModel urlMatchModel = new UrlMatchModel(requestURL, _up);
            if (urlMatchModel.isMatched()) {
                if (urlMatchModel.isPatternExt()) {
                    if (extRef.get() != null) {
                        throw new MRestMappingException(
                                String.format("%s found more than one servlet mapping handler for url: %s, urlPattern: %s|%s"
                                        , getContextDesc(), requestURL, extRef.get().getUrlPatternModel().getUrlPattern(), urlMatchModel.getUrlPattern()));
                    }
                    extRef.set(urlMappingServlet);
                }
                if (urlMatchModel.isPatternPathMatch()) {
                    if (pathMatchRef.get() != null) {
                        throw new MRestMappingException(
                                String.format("%s found more than one servlet mapping handler for url: %s, urlPattern: %s|%s"
                                        , getContextDesc(), requestURL, pathMatchRef.get().getUrlPatternModel().getUrlPattern(), urlMatchModel.getUrlPattern()));
                    }
                    pathMatchRef.set(urlMappingServlet);
                }
                if (urlMatchModel.isPatternStrictly()) {
                    if (urlMatchModel.getUrlPatternModel().isSupportPlaceholder()) {
                        if (strictlyRef0.get() != null) {
                            throw new MRestMappingException(
                                    String.format("%s found more than one servlet mapping handler for url: %s, urlPattern: %s|%s"
                                            , getContextDesc(), requestURL, strictlyRef0.get().getUrlPatternModel().getUrlPattern(), urlMatchModel.getUrlPattern()));
                        }
                        SharedObjects.getServerThreadModel().getRestRequest().addPlaceholderKv(urlMatchModel.getPlaceholderMap());
                        strictlyRef0.set(urlMappingServlet);
                    } else {
                        if (strictlyRef1.get() != null) {
                            throw new MRestMappingException(
                                    String.format("%s found more than one servlet mapping handler for url: %s, urlPattern: %s|%s"
                                            , getContextDesc(), requestURL, strictlyRef1.get().getUrlPatternModel().getUrlPattern(), urlMatchModel.getUrlPattern()));
                        }
                        strictlyRef1.set(urlMappingServlet);
                    }
                }
            }
        });
        if (strictlyRef1.get() != null) {
            mappingServletList.add(strictlyRef1.get());
        }
        if (strictlyRef0.get() != null && pathMatchRef.get() != null) {
            UrlMappingServlet servlet0 = strictlyRef0.get();
            UrlMappingServlet servlet1 = pathMatchRef.get();
            // 路径匹配度
            int count0 = servlet0.getUrlPatternModel().getActualPathMatchCount(requestURL);
            int count1 = servlet1.getUrlPatternModel().getActualPathMatchCount(requestURL);
            if (count0 == count1) {
                throw new MRestMappingException(
                        String.format("%s found more than one servlet mapping handler for url: %s, urlPattern: %s|%s"
                                , getContextDesc(), requestURL, servlet0.getUrlPatternModel().getUrlPattern(), servlet1.getUrlPatternModel().getUrlPattern()));
            }
            // 相同匹配模式 ((/*)|(\\S+)*)* 优先选择路径匹配度高的匹配模式
            mappingServletList.add(count0 > count1 ? servlet0 : servlet1);
        } else {
            if (strictlyRef0.get() != null) {
                mappingServletList.add(strictlyRef0.get());
            }
            if (pathMatchRef.get() != null) {
                mappingServletList.add(pathMatchRef.get());
            }
        }
        if (extRef.get() != null) {
            mappingServletList.add(extRef.get());
        }
        if (mappingServletList.isEmpty()) {
            return null;
        }
        return mappingServletList.get(0).getRestServlet();
    }

    public synchronized MRestContext servlet(MRestServlet... servletArr) {
        for (MRestServlet servlet: servletArr) {
            servlet(servlet);
        }
        return this;
    }

    public synchronized MRestContext servlet(MRestServlet servlet) {
        if (servlet instanceof AbstractRestServlet) {
            AbstractRestServlet restServlet = (AbstractRestServlet) servlet;
            List urlList = restServlet.getMappingUrlList();
            urlList.forEach(url -> {
                servlet(url, servlet);
            });
            return this;
        }
        return servlet(servlet.urlPattern(), servlet);
    }

    /**
     * 三种匹配规则:
     * 1、精确匹配:确定url进行匹配,例:/user/id
     * 2、路径匹配:以"/"开头并以"/*"结尾,例:/*,/user/*
     * 3、扩展名匹配,以"*."开头的字符串用于拓展名匹配,例:*.do
     * @param urlPattern 匹配规则
     * @param servlet servlet实例
     * @return MRestContext
     */
    public synchronized MRestContext servlet(String urlPattern, MRestServlet servlet) {
        getRestServer().checkServerState();
        servletTaskList.add(() -> {
            UrlPatternModel urlPatternModel = new UrlPatternModel(urlPattern);
            String $urlPattern = urlPatternModel.getUrlPattern();
            List urlPatternModelList = servletMap.values().stream().map(UrlMappingServlet::getUrlPatternModel).collect(Collectors.toList());
            for (UrlPatternModel patternModel: urlPatternModelList) {
                if (patternModel.equals(urlPatternModel)) {
                    throw new MRestMappingException(String.format("%s mapping servlet conflict, urlPattern: %s | %s", getContextDesc(), $urlPattern, patternModel.getUrlPattern()));
                }
            }
            MRestServlet restServlet = Objects.requireNonNull(servlet);
            servletMap.put($urlPattern, new UrlMappingServlet(urlPatternModel, restServlet));
            if (logger.isInfoEnabled()) {
                logger.info("{} register servlet success, {} -> {}", getContextDesc(), $urlPattern, restServlet.servletName());
            }
        });
        return this;
    }

    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 order0 - order1;
        });
        filterList.addLast(staticResourceFilter);
        MRestServlet servlet = getServlet(requestURL);
        // servlet包装为filter执行
        if (servlet != null) {
            filterList.addLast(new MRestServletAdapter() {
                @Override
                public void doFilter(MRestRequest request, MRestResponse response, MRestFilterChain filterChain) {
                    servlet.service(request, response);
                    // servlet执行完成,不在filterChain中向后路由
                    // write方法未执行过, 直接返回成功状态码
                    if (!response.isWriteMethodInvoked()) {
                        response.write(HttpResponseStatus.OK);
                    }
                }
            });
        }
        // 最后才走到分发处理.
        filterList.addLast((request, response, filterChain) -> {
            dispatchServlet.service(request, response);
        });
        return new MRestFilterChain(this, filterList.toArray(new MRestFilter[0]));
    }

    /**
     * 添加filter, 自动扫描filter注解, 获取urlPattern.
     * @param filterArr filterArr
     * @return MRestContext
     */
    public synchronized MRestContext 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, 根据传入urlPattern来进行匹配.
     * @param urlPattern urlPattern
     * @param filterArr filterArr
     * @return MRestContext
     */
    public synchronized MRestContext filter(String urlPattern, MRestFilter... filterArr) {
        for (MRestFilter filter: filterArr) {
            filter0(filter, urlPattern);
        }
        return this;
    }

    /**
     * 添加filter, 一次指定多个urlPattern.
     * @param filter filter
     * @param urlPatterns urlPattern array.
     * @return MRestContext
     */
    public synchronized MRestContext filter(MRestFilter filter, String... urlPatterns) {
        return filter0(filter, urlPatterns);
    }

    private synchronized MRestContext filter0(MRestFilter filter, String... urlPatterns) {
        getRestServer().checkServerState();
        filterTaskList.add(() -> {
            MRestFilter restFilter = Objects.requireNonNull(filter);
            if (urlPatterns.length == 0) {
                throw new IllegalArgumentException(String.format("%s can't assign empty urlPatterns to filter: %s", getContextDesc(), filter.filterName()));
            }
            for (String urlPattern: urlPatterns) {
                filterMap.computeIfAbsent(urlPattern, k -> new ArrayList<>()).add(restFilter);
                if (logger.isInfoEnabled()) {
                    logger.info("{} register filter success, {} -> {}", getContextDesc(), urlPattern, filter.filterName());
                }
            }
        });
        return this;
    }

    public MRestContext addDefaultClasspathResource() {
        return addDefaultClasspathResource(Constants.ROOT_PATH);
    }

    public MRestContext addDefaultClasspathResource(String prefixUrl) {
        return addClasspathResources(prefixUrl,
                MRestUtils.getDefaultServerConfig().getClasspathResources().toArray(new String[0]));
    }

    public MRestContext addClasspathResource(String path) {
        return addClasspathResource(Constants.ROOT_PATH, path);
    }

    public MRestContext addClasspathResource(String prefixUrl, String path) {
        return addClasspathResources(prefixUrl, new String[] { path });
    }

    public MRestContext addClasspathResources(String[] pathArr) {
        return addClasspathResources(Constants.ROOT_PATH, pathArr);
    }

    public synchronized MRestContext addClasspathResources(String prefixUrl, String[] pathArr) {
        if (pathArr != null) {
            String _prefixUrl = formatPrefixUrl(prefixUrl);
            for (String path: pathArr) {
                classpathResources.computeIfAbsent(_prefixUrl, k -> new HashSet<>()).add(formatClasspathResourcePath(path));
            }
        }
        return this;
    }

    private String formatClasspathResourcePath(String path) {
        String location = String.valueOf(path).trim();
        if (!location.endsWith(Constants.PATH_SEP)) {
            location = location + Constants.PATH_SEP;
        }
        while (location.startsWith(Constants.PATH_SEP) && location.length() > 1) {
            location = location.substring(1);
        }
        return location;
    }

    public synchronized Map> getClasspathResources() {
        Map> map = new HashMap<>();
        classpathResources.forEach((key, value) -> {
            List list = new ArrayList<>();
            if (value != null) {
                list.addAll(value);
            }
            map.put(key, list);
        });
        return map;
    }

    public MRestContext addDiskResource(String path) {
        return addDiskResource(Constants.ROOT_PATH, path);
    }

    public MRestContext addDiskResource(String prefixUrl, String path) {
        return addDiskResources(prefixUrl, new String[] { path });
    }

    public MRestContext addDiskResources(String[] pathArr) {
        return addDiskResources(Constants.ROOT_PATH, pathArr);
    }

    public synchronized MRestContext addDiskResources(String prefixUrl, String[] pathArr) {
        if (pathArr != null) {
            String _prefixUrl = formatPrefixUrl(prefixUrl);
            for (String path: pathArr) {
                diskResources.computeIfAbsent(_prefixUrl, k -> new HashSet<>()).add(formatDiskResourcePath(path));
            }
        }
        return this;
    }

    private String formatDiskResourcePath(String path) {
        return path;
    }

    public synchronized Map> getDiskResources() {
        Map> map = new HashMap<>();
        diskResources.forEach((key, value) -> {
            List list = new ArrayList<>();
            if (value != null) {
                list.addAll(value);
            }
            map.put(key, list);
        });
        return map;
    }

    private String formatPrefixUrl(String prefixUrl) {
        String _prefixUrl = String.valueOf(prefixUrl).replace(Constants.PATH_SEP_WIN, Constants.PATH_SEP);
        while (_prefixUrl.endsWith(Constants.PATH_SEP) && _prefixUrl.length() > 1) {
            _prefixUrl = _prefixUrl.substring(0, _prefixUrl.length() - 1);
        }
        if (!_prefixUrl.startsWith(Constants.PATH_SEP)) {
            _prefixUrl = Constants.PATH_SEP + _prefixUrl;
        }
        return _prefixUrl;
    }


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


    private Consumer defaultErrorHandler = null;

    public Consumer getDefaultErrorHandler() {
        return defaultErrorHandler;
    }

    public MRestContext defaultErrorHandler(Consumer defaultErrorHandler) {
        this.defaultErrorHandler = Objects.requireNonNull(defaultErrorHandler);
        return this;
    }

    private Supplier objectMapperSupplier;

    public MRestContext setObjectMapperSupplier(Supplier objectMapperSupplier) {
        this.objectMapperSupplier = Objects.requireNonNull(objectMapperSupplier);
        return this;
    }

    public Supplier getObjectMapperSupplier() {
        return objectMapperSupplier;
    }

    private volatile boolean autoRefreshStaticResources = false;
    private static final long DEFAULT_REFRESH_PERIOD = 60*1000L;
    private volatile long autoRefreshStaticResourcesPeriod = DEFAULT_REFRESH_PERIOD;

    public synchronized MRestContext autoRefreshStaticResources(boolean autoRefreshStaticResources) {
        return autoRefreshStaticResources(autoRefreshStaticResources, DEFAULT_REFRESH_PERIOD);
    }

    public synchronized MRestContext autoRefreshStaticResources(boolean autoRefreshStaticResources, long autoRefreshStaticResourcesPeriod) {
        if (autoRefreshStaticResourcesPeriod <= 0) {
            throw new IllegalArgumentException();
        }
        restServer.checkServerState();
        this.autoRefreshStaticResources = autoRefreshStaticResources;
        this.autoRefreshStaticResourcesPeriod = autoRefreshStaticResourcesPeriod;
        return this;
    }

    public boolean isAutoRefreshStaticResources() {
        return autoRefreshStaticResources;
    }

    public long getAutoRefreshStaticResourcesPeriod() {
        return autoRefreshStaticResourcesPeriod;
    }

    private volatile String indexUrl = null;

    public synchronized MRestContext setIndexUrl(String indexUrl) {
        restServer.checkServerState();
        this.indexUrl = Objects.requireNonNull(indexUrl).trim();
        return this;
    }

    public String getIndexUrl() {
        return indexUrl;
    }

    public MWebsocketContext websocketContext() {
        return websocketContext(Constants.DEFAULT_WEBSOCKET_CONTEXT_PATH);
    }

    public synchronized MWebsocketContext websocketContext(String websocketUrl) {
        MWebsocketContext websocketContext = getWebsocketContext(websocketUrl);
        if (websocketContext == null) {
            String _ctxPath = MRestUtils.formatPath(websocketUrl);
            websocketContext = new MWebsocketContext(this.restServer, this, _ctxPath);
            websocketContextMap.put(_ctxPath, websocketContext);
        }
        return websocketContext;
    }

    public List getWebsocketContextList() {
        return new ArrayList<>(websocketContextMap.keySet());
    }

    public MWebsocketContext getWebsocketContext(String websocketUrl) {
        return websocketContextMap.get(MRestUtils.formatPath(websocketUrl));
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy