com.jk.web.embedded.JKWebApplication Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jk-framework-standalone Show documentation
Show all versions of jk-framework-standalone Show documentation
A wrapper for tomcat webserver that enables faster web application development in Java
/*
* 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.
*/
}