001/**
002 * Copyright (c) 2015-2022, Michael Yang 杨福海 (fuhai999@gmail.com).
003 * <p>
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * <p>
008 * http://www.apache.org/licenses/LICENSE-2.0
009 * <p>
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package io.jboot.app.undertow;
017
018import com.jfinal.server.undertow.PropExt;
019import com.jfinal.server.undertow.UndertowConfig;
020import com.jfinal.server.undertow.hotswap.HotSwapResolver;
021import io.jboot.app.config.JbootConfigManager;
022
023import java.io.IOException;
024import java.net.ServerSocket;
025
026public class JbootUndertowConfig extends UndertowConfig {
027
028    protected static final String DEV_MODE = "undertow.devMode";
029    protected static final String UNDERTOW_PORT = "undertow.port";
030    protected static final String UNDERTOW_HOST = "undertow.host";
031    protected static final String UNDERTOW_RESOURCEPATH = "undertow.resourcePath";
032
033
034    public JbootUndertowConfig(Class<?> jfinalConfigClass) {
035        super(jfinalConfigClass);
036    }
037
038    public JbootUndertowConfig(String jfinalConfigClass) {
039        super(jfinalConfigClass);
040    }
041
042    public JbootUndertowConfig(Class<?> jfinalConfigClass, String undertowConfig) {
043        super(jfinalConfigClass, undertowConfig);
044    }
045
046    public JbootUndertowConfig(String jfinalConfigClass, String undertowConfig) {
047        super(jfinalConfigClass, undertowConfig);
048    }
049
050    @Override
051    protected PropExt createPropExt(String undertowConfig) {
052
053        PropExt propExt = super.createPropExt(undertowConfig)
054                .append(new PropExt(JbootConfigManager.me().getProperties()));
055
056        String port = propExt.get(UNDERTOW_PORT);
057
058        //当不配置端口号时,默认为 8080
059        if (port == null || port.trim().length() == 0) {
060            propExt.getProperties().put(UNDERTOW_PORT, "8080");
061            JbootConfigManager.setBootArg(UNDERTOW_PORT, "8080");
062        }
063
064        //当配置为 -1 或者 * 时,默认为随机端口号
065        else if ((port.trim().equals("*") || port.trim().equals("-1"))) {
066            Integer availablePort = getAvailablePort();
067            if (availablePort != null) {
068                propExt.getProperties().put(UNDERTOW_PORT, availablePort.toString());
069                JbootConfigManager.setBootArg(UNDERTOW_PORT, availablePort.toString());
070            }
071        }
072
073        //当不配置 undertow 开发模式时,默认开发模式为 devMode
074        String devMode = propExt.get(DEV_MODE);
075        if (devMode == null || devMode.trim().length() == 0) {
076            propExt.getProperties().put(DEV_MODE, JbootConfigManager.me().isDevMode());
077        }
078
079        //当不配置 host 时,为其配置默认的 host
080        String host = propExt.get(UNDERTOW_HOST);
081        if (host == null || host.trim().length() == 0) {
082            if (isAppDevMode()) {
083                propExt.getProperties().put(UNDERTOW_HOST, "localhost");
084                JbootConfigManager.setBootArg(UNDERTOW_HOST, "localhost");
085            } else {
086                propExt.getProperties().put(UNDERTOW_HOST, "0.0.0.0");
087                JbootConfigManager.setBootArg(UNDERTOW_HOST, "0.0.0.0");
088            }
089        }
090
091        //当不配置资源路径时,默认为 classpath 下的 webapp
092        String resPath = propExt.get(UNDERTOW_RESOURCEPATH);
093        if (resPath == null || resPath.trim().length() == 0) {
094            propExt.getProperties().put(UNDERTOW_RESOURCEPATH, "classpath:webapp," + this.resourcePath);
095        }
096
097        return propExt;
098    }
099
100    /**
101     * 获取随机可用的端口号
102     *
103     * @return
104     */
105    private static Integer getAvailablePort() {
106        ServerSocket serverSocket = null;
107        try {
108            serverSocket = new ServerSocket(0);
109            return serverSocket.getLocalPort();
110        } catch (IOException e) {
111        } finally {
112            if (serverSocket != null) {
113                try {
114                    serverSocket.close();
115                } catch (IOException e) {
116                }
117            }
118        }
119        return null;
120    }
121
122
123    private static boolean isAppDevMode() {
124        String appMode = JbootConfigManager.me().getConfigValue("jboot.app.mode");
125        return (null == appMode || "".equals(appMode.trim()) || "dev".equalsIgnoreCase(appMode.trim()));
126    }
127
128
129    @Override
130    public HotSwapResolver getHotSwapResolver() {
131        if (hotSwapResolver == null) {
132            hotSwapResolver = new JbootHotSwapResolver(getClassPathDirs());
133            // 后续将此代码转移至 HotSwapResolver 中去,保持 UndertowConfig 的简洁
134            if (hotSwapClassPrefix != null) {
135                for (String prefix : hotSwapClassPrefix.split(",")) {
136                    if (notBlank(prefix)) {
137                        hotSwapResolver.addHotSwapClassPrefix(prefix);
138                    }
139                }
140            }
141        }
142        return hotSwapResolver;
143    }
144}
145