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

com.jk.web.embedded.JKWebApplication Maven / Gradle / Ivy

Go to download

A wrapper for tomcat webserver that enables faster web application development in Java

There is a newer version: 7.0.0-M7
Show newest version
/*
 * Copyright 2002-2021 Dr. Jalal Kiswani. 
 * Email: [email protected]
 * Check out https://smart-api.com for more details
 * 
 * All the opensource projects of Dr. Jalal Kiswani are free for personal and academic use only, 
 * for commercial usage and support, please contact the author.
 *
 * 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.jk.web.embedded;

import java.io.File;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Deque;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.catalina.LifecycleState;
import org.apache.catalina.WebResourceRoot;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.startup.Tomcat;
import org.apache.catalina.webresources.DirResourceSet;
import org.apache.catalina.webresources.StandardRoot;
import org.apache.tomcat.JarScanType;
import org.apache.tomcat.JarScannerCallback;
import org.apache.tomcat.jni.OS;
import org.apache.tomcat.util.scan.StandardJarScanFilter;
import org.apache.tomcat.util.scan.StandardJarScanner;
import org.slf4j.bridge.SLF4JBridgeHandler;
import org.springframework.util.StringUtils;

import com.jk.core.logging.JKLogger;
import com.jk.core.logging.JKLoggerFactory;
import com.jk.core.util.JK;
import com.jk.core.util.JKConversionUtil;
import com.jk.core.util.JKIOUtil;
import com.jk.web.embedded.spring.TldSkipPatterns;

// TODO: Auto-generated Javadoc
/**
 * The Class JKWebApplication.
 */
public class JKWebApplication {

	/** The Constant JK_WEBSERVER_PORT_KEY. */
	private static final String JK_WEBSERVER_PORT_KEY = "JK.WEBSERVER.PORT";

	/** The Constant DEFAULT_WEBSERVER_PORT. */
	private static final String DEFAULT_WEBSERVER_PORT = "8080";

	/** The Constant DEFAULT_WEB_APP_FOLDER. */
	private static final String DEFAULT_WEB_APP_FOLDER = "src/main/webapp/";

	/** The Constant DEFAULT_TEMP_WEBAPP_FOLDER. */
	private static final String DEFAULT_TEMP_WEBAPP_FOLDER = "jk-webapp-";
	// THE NAME IS THE DIRECTORT INSIDE THE SOURCE CODE, that contains the web
	/** The Constant RESOURCES_WEB_FOLDER. */
	// resources.
	private static final String RESOURCES_WEB_FOLDER = "jk/webapp";

	/** The logger. */
	static JKLogger logger = JKLoggerFactory.getLogger(JKWebApplication.class);

	/**
	 * Run.
	 */
	public static void run() {
		String webPort = System.getenv(JK_WEBSERVER_PORT_KEY);
		if (webPort == null || webPort.isEmpty()) {
			logger.debug("Port config not founds, default port will be used : " + DEFAULT_WEBSERVER_PORT);
			webPort = DEFAULT_WEBSERVER_PORT;
		}
		run(JKConversionUtil.toInteger(webPort));
	}

	/**
	 * Run.
	 *
	 * @param portNumber the port number
	 */
	public static void run(int portNumber) {
		run(portNumber, true);
	}
	
	/**
	 * Run.
	 *
	 * @param portNumber the port number
	 * @param autoOpenBrowser the auto open browser
	 */
	public static void run(int portNumber, boolean autoOpenBrowser) {
		run(portNumber,autoOpenBrowser,"");
	}

	/**
	 * Run.
	 *
	 * @param portNumber      the port number
	 * @param autoOpenBrowser the auto open browser
	 * @param context the context
	 */
	public static void run(int portNumber, boolean autoOpenBrowser, String context) {
		JK.init();
		closeInstance(portNumber);
		try {
			String webappDirLocation = DEFAULT_WEB_APP_FOLDER;
			if (!JK.exists(webappDirLocation)) {
				webappDirLocation = JKIOUtil.createTempDirectory().getAbsolutePath();
			}
			File rootFolder = new File(webappDirLocation);
			logger.debug("Creating tomcat instance");
			Tomcat tomcat = new Tomcat();

			// The port that we should run on can be set into an environment variable
			// Look for that variable and default to 8080 if it isn't there.

			tomcat.setPort(Integer.valueOf(portNumber));

			StandardContext ctx = (StandardContext) tomcat.addWebapp(context, rootFolder.getAbsolutePath());

			StandardJarScanFilter jarScanFilter = new StandardJarScanFilter() {
				@Override
				public boolean check(JarScanType jarScanType, String jarName) {
					boolean check = super.check(jarScanType, jarName);
					logger.trace("Checking ({}) of type ({}), result: ({})", jarName, jarScanType, check);
					return check;
				}
			};
			jarScanFilter.setTldSkip(StringUtils.collectionToCommaDelimitedString(TldSkipPatterns.DEFAULT));
			jarScanFilter.setPluggabilitySkip(StringUtils.collectionToCommaDelimitedString(TldSkipPatterns.DEFAULT));

			StandardJarScanner scanner = new StandardJarScanner() {
				@Override
				protected void process(JarScanType scanType, JarScannerCallback callback, URL url, String webappPath,
						boolean isWebapp, Deque classPathUrlsToProcess) throws IOException {
					// IMPORTANT: the the webApp flag should be switched to true to make the
					// web-fragments discroverable.
					// By default: tomcat scan jars in the WEB-INF/lib folders for fragments, but
					// when running from inside the
					// IDE, the lib folder is not populated, thats why we need this hack.
					logger.trace("scanType({}), callback({}), url({}), webappPath, ({}), classPathUrlsToProcess ({})",
							scanType, callback, url, webappPath, true, classPathUrlsToProcess);
					super.process(scanType, callback, url, webappPath, true, classPathUrlsToProcess);
				}
			};

			scanner.setJarScanFilter(jarScanFilter);
			ctx.setJarScanner(scanner);

			logger.debug("configuring app with basedir: " + new File("./" + webappDirLocation).getAbsolutePath());

			// Declare an alternative location for your "WEB-INF/classes" dir
			// Servlet 3.0 annotation will work
//			resources.setCachingAllowed(false);
			File additionWebInfClasses = new File("target/classes");
//			if (file.exists()) {
			logger.debug("Setting tomcat to read classes from target/classes");
//			File additionWebInfClasses = file;
			WebResourceRoot resources = new StandardRoot(ctx);
			resources.addPreResources(
					new DirResourceSet(resources, "/WEB-INF/classes", additionWebInfClasses.getAbsolutePath(), "/"));
			ctx.setResources(resources);
//			}
			logger.info("Starting web-server at port {}....", portNumber);
			tomcat.start();
			final ServerSocket shutdownServer = new ServerSocket(getClosePortDeamon(portNumber));
			Thread thread = new Thread() {
				@Override
				public void run() {
					try {
						shutdownServer.accept();
						logger.info("Web server received a stop signal");
						System.exit(0);
					} catch (Exception e) {
					}
				}
			};
			thread.start();

			Runtime.getRuntime().addShutdownHook(new Thread() {
				@Override
				public void run() {
					if (tomcat != null && tomcat.getServer().getState() == LifecycleState.STARTED) {
						logger.debug("Trying to stop tomcat...");
						try {
							tomcat.getServer().stop();
						} catch (Exception e) {
						}
						try {
							shutdownServer.close();
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}
			});
			logger.info("Web server started at URL :  http://localhost:{}", portNumber);
			if (autoOpenBrowser) {
				JKIOUtil.executeFile("start http://localhost:" + portNumber+"/"+context);
			}
		} catch (Exception e) {
			JK.throww(e);
		}

	}

	/**
	 * Clean up previous instance.
	 *
	 * @param portNumber the port number
	 */
	public static void closeInstance(int portNumber) {
		try {
			Socket client = new Socket("localhost", getClosePortDeamon(portNumber));
			Thread.sleep(1000);
			client.close();
		} catch (Exception e) {
		}
	}

	/**
	 * Gets the close port deamon.
	 *
	 * @param portNumber the port number
	 * @return the close port deamon
	 */
	protected static int getClosePortDeamon(int portNumber) {
		return portNumber + 1;
	}

	/**
	 * Inits the loggers.
	 */

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy