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

com.jfinal.server.jetty.JettyServer Maven / Gradle / Ivy

There is a newer version: 2019.3
Show newest version
/**
 * Copyright (c) 2011-2019, James Zhan 詹波 ([email protected]).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.jfinal.server.jetty;

import java.io.File;
import java.io.IOException;
import java.net.DatagramSocket;
import java.net.ServerSocket;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.session.FileSessionDataStoreFactory;
import org.eclipse.jetty.webapp.WebAppContext;
import com.jfinal.core.Const;
import com.jfinal.kit.FileKit;
import com.jfinal.kit.LogKit;
import com.jfinal.kit.PathKit;
import com.jfinal.kit.StrKit;
import com.jfinal.server.IServer;

/**
 * JettyServer is used to config and start jetty web server.
 * Jetty version 9.4.12.v20180830
 */
class JettyServer implements IServer {
	
	private String webAppDir;
	private int port;
	private String context;
	private int scanIntervalSeconds;
	private boolean running = false;
	private Server server;
	private WebAppContext webApp;
	
	JettyServer(String webAppDir, int port, String context, int scanIntervalSeconds) {
		if (webAppDir == null) {
			throw new IllegalStateException("Invalid webAppDir of web server: " + webAppDir);
		}
		if (port < 0 || port > 65535) {
			throw new IllegalArgumentException("Invalid port of web server: " + port);
		}
		if (StrKit.isBlank(context)) {
			throw new IllegalStateException("Invalid context of web server: " + context);
		}
		
		this.webAppDir = webAppDir;
		this.port = port;
		this.context = context;
		this.scanIntervalSeconds = scanIntervalSeconds;
	}
	
	public void start() {
		if (!running) {
			try {
				running = true;
				doStart();
			} catch (Exception e) {
				System.err.println(e.getMessage());
				LogKit.error(e.getMessage(), e);
			}
		}
	}
	
	public void stop() {
		if (running) {
			try {server.stop();} catch (Exception e) {LogKit.error(e.getMessage(), e);}
			running = false;
		}
	}
	
	private void doStart() {
		if (!available(port)) {
			throw new IllegalStateException("port: " + port + " already in use!");
		}
		
		deleteSessionData();
		
		System.out.println("Starting JFinal " + Const.JFINAL_VERSION);
		server = new Server();
		ServerConnector connector = new ServerConnector(server);
		connector.setPort(port);
		server.addConnector(connector);
		webApp = new WebAppContext();
		
		
		// webApp.addSystemClass("sun.");
		// webApp.addSystemClass("com.sun.");
		webApp.getSystemClasspathPattern().add("sun.");				// 支持 IDEA
		webApp.getSystemClasspathPattern().add("com.sun.");
		webApp.getSystemClasspathPattern().add("org.apache.");		// 支持 jsp
		webApp.getSystemClasspathPattern().add("org.glassfish.");	// 支持 jsp
		
		
		webApp.setThrowUnavailableOnStartupException(true);	// 在启动过程中允许抛出异常终止启动并退出 JVM
		webApp.setContextPath(context);
		webApp.setResourceBase(webAppDir);	// webApp.setWar(webAppDir);
		webApp.setInitParameter("org.eclipse.jetty.servlet.Default.dirAllowed", "false");
		webApp.setInitParameter("org.eclipse.jetty.servlet.Default.useFileMappedBuffer", "false");	// webApp.setInitParams(Collections.singletonMap("org.mortbay.jetty.servlet.Default.useFileMappedBuffer", "false"));
		webApp.setMaxFormContentSize(128 * 1024 * 1024);
		
		persistSession(server);	// persistSession(webApp);
		
		server.setHandler(webApp);
		
		server.setStopAtShutdown(true);
		server.setDumpAfterStart(false);
		server.setDumpBeforeStop(false);
		
		// configureScanner
		if (scanIntervalSeconds > 0) {
		    //only need to change classloader when scanIntervalSeconds > 0
            changeClassLoader(webApp);
            
			Scanner scanner = new Scanner(PathKit.getRootClassPath(), scanIntervalSeconds) {
				public void onChange() {
					try {
						System.err.println("\nLoading changes ......");
						webApp.stop();
						JFinalClassLoader loader = new JFinalClassLoader(webApp, getClassPath());
						webApp.setClassLoader(loader);
						webApp.start();
						System.err.println("Loading complete (^_^)");
					} catch (Exception e) {
						System.err.println("Error reconfiguring/restarting webapp after change in watched files");
						LogKit.error(e.getMessage(), e);
					}
				}
			};
			System.out.println("Starting scanner at interval of " + scanIntervalSeconds + " seconds");
			scanner.start();
		}
		
		try {
			System.out.println("Starting Jetty Server " + Server.getVersion() + " on port: " + port);
			server.start();
			System.out.println("Starting Complete. Welcome To The JFinal World (^_^)");
			server.join();
		} catch (Exception e) {
			LogKit.error(e.getMessage(), e);
			System.exit(100);
		}
		return;
	}
	
	private void changeClassLoader(WebAppContext webApp) {
		try {
			String classPath = getClassPath();
			JFinalClassLoader jfcl = new JFinalClassLoader(webApp, classPath);
			// jfcl.addClassPath(classPath);
			webApp.setClassLoader(jfcl);
		} catch (IOException e) {
			LogKit.error(e.getMessage(), e);
		}
	}
	
	private String getClassPath() {
		return System.getProperty("java.class.path");
	}
	
	private void deleteSessionData() {
		try {
			FileKit.delete(new File(getStoreDir()));
		}
		catch (Exception e) {
			LogKit.logNothing(e);
		}
	}
	
	private String getStoreDir() {
		String storeDir = PathKit.getWebRootPath() + "/../../session_data" + context;
		if ("\\".equals(File.separator)) {
			storeDir = storeDir.replaceAll("/", "\\\\");
		}
		return storeDir;
	}
	
	private void persistSession(Server server) {
		String storeDir = getStoreDir();
		FileSessionDataStoreFactory fsdsf = new FileSessionDataStoreFactory();
		fsdsf.setStoreDir(new File(storeDir));
		server.addBean(fsdsf);
	}
	
	/* 改用 server.addBean(fsdsf) 实现
	private void persistSession(WebAppContext webApp) {
		// http://www.eclipse.org/jetty/documentation/current/session-management.html
		String storeDir = getStoreDir();
		SessionCache sc = webApp.getSessionHandler().getSessionCache();
		if (sc != null) {
			SessionDataStore sds = sc.getSessionDataStore();
			if (sds instanceof FileSessionDataStore) {
				FileSessionDataStore fsd = (FileSessionDataStore)sds;
				fsd.setStoreDir(new File(storeDir));
				return ;
			}
		}
		
		
		SessionHandler sessionHandler = webApp.getSessionHandler();
		if (sessionHandler == null) {
			sessionHandler = new SessionHandler();
			webApp.setSessionHandler(sessionHandler);
		}
		
		FileSessionDataStoreFactory fsdsf = new FileSessionDataStoreFactory();
		fsdsf.setStoreDir(new File(storeDir));
		SessionDataStore sessionDataStore = fsdsf.getSessionDataStore(sessionHandler);
		
		DefaultSessionCacheFactory dscf = new DefaultSessionCacheFactory();
		SessionCache sessionCache = dscf.getSessionCache(sessionHandler);
		sessionCache.setSessionDataStore(sessionDataStore);
		
		sessionHandler.setSessionCache(sessionCache);
	} */
	
	private static boolean available(int port) {
		if (port <= 0) {
			throw new IllegalArgumentException("Invalid start port: " + port);
		}
		
		ServerSocket ss = null;
		DatagramSocket ds = null;
		try {
			ss = new ServerSocket(port);
			ss.setReuseAddress(true);
			ds = new DatagramSocket(port);
			ds.setReuseAddress(true);
			return true;
		} catch (IOException e) {
			LogKit.logNothing(e);
		} finally {
			if (ds != null) {
				ds.close();
			}
			
			if (ss != null) {
				try {
					ss.close();
				} catch (IOException e) {
					// should not be thrown, just detect port available.
					LogKit.logNothing(e);
				}
			}
		}
		return false;
	}
}










© 2015 - 2024 Weber Informatics LLC | Privacy Policy