com.sun.grizzly.http.servlet.deployer.GrizzlyWebServerDeployer Maven / Gradle / Ivy
/**
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. *
* Copyright 2007-2008 Sun Microsystems, Inc. All rights reserved. *
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code. If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*
*/
package com.sun.grizzly.http.servlet.deployer;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.Filter;
import javax.servlet.Servlet;
import com.sun.grizzly.arp.AsyncHandler;
import com.sun.grizzly.arp.DefaultAsyncHandler;
import com.sun.grizzly.comet.CometAsyncFilter;
import com.sun.grizzly.http.SelectorThread;
import com.sun.grizzly.http.embed.GrizzlyWebServer;
import com.sun.grizzly.http.embed.GrizzlyWebServer.PROTOCOL;
import com.sun.grizzly.http.servlet.ServletAdapter;
import com.sun.grizzly.http.servlet.deployer.comparator.WarFileComparator;
import com.sun.grizzly.http.webxml.WebappLoader;
import com.sun.grizzly.http.webxml.schema.FilterMapping;
import com.sun.grizzly.http.webxml.schema.InitParam;
import com.sun.grizzly.http.webxml.schema.Listener;
import com.sun.grizzly.http.webxml.schema.ServletMapping;
import com.sun.grizzly.http.webxml.schema.WebApp;
import com.sun.grizzly.util.ClassLoaderUtil;
import com.sun.grizzly.util.ExpandJar;
/*
* We have 4 cases :
*
* #1 - war
* #2 - web.xml
* #3 - folder that contains at least one war
* #4 - folder of a deployed war (will use the /WEB-INF/web.xml)
*
* if #3 find war, it will deployed it, if not, will try #4 if it found nothing, #2
*/
public class GrizzlyWebServerDeployer {
protected static Logger logger = Logger.getLogger("GrizzlyWebServerDeployerLogger");
public static final String DEFAULT_CONTEXT = "/";
public static final String WEB_XML_PATH = "WEB-INF" + File.separator + "web.xml";
private GrizzlyWebServer ws = null;
private String locations;
private String webxmlPath;
private String libraryPath;
private String forcedContext;
private boolean waitToStart = false;
private boolean cometEnabled = false;
private boolean forceWarDeployment = false;
private boolean ajpEnabled = false;
private List deployedApplicationList = null;
private int port = 8080;
public void init(String args[]) throws MalformedURLException, IOException, Exception {
if (args.length == 0) {
printHelpAndExit();
}
// parse options
parseOptions(args);
deployedApplicationList = new ArrayList();
}
private void deployWar(String location) throws Exception {
webxmlPath = appendWarContentToClassPath(location);
deploy(webxmlPath, getContext(webxmlPath), webxmlPath + WEB_XML_PATH);
}
private void deployServlet(String location) throws Exception{
deployServlet(location, null);
}
private void deployServlet(String location, String context) throws Exception {
if(context==null){
context = getContext("/");
}
webxmlPath = appendWarContentToClassPath(null);
deploy(null, context, location);
}
private void deployExpandedWar(String location) throws Exception {
webxmlPath = appendWarContentToClassPath(location);
deploy(webxmlPath, getContext(webxmlPath), webxmlPath + WEB_XML_PATH);
}
private Map getFile(String location){
// remove ending slash if any
// we need to check if the location is not "/"
if (location.endsWith("/") && location.length() > 1) {
location = location.substring(0, location.length() - 1);
}
// we try to look of the file's list
File folder = new File(location);
if (!folder.exists() || !folder.isDirectory()) {
return null;
}
// we only want folders that contains WEB-INF or war files
File files[] = folder.listFiles(new FilenameFilter() {
public boolean accept(File dir, String name) {
if (name.endsWith(".war")) {
return true;
} else {
// we can have 2 options. First, this folder contains a
// WEB-INF
// Second : contains only folder possibly webapps
// Option1
if (name.equals("WEB-INF")) {
return true;
} else {
// Option2
File file = new File(dir + File.separator + name + File.separator + "WEB-INF");
if ((file.exists() && file.isDirectory())) {
return true;
}
}
return false;
}
}
});
// do we have something to deploy
if (files == null || files.length == 0) {
return null;
}
// sort list. We want expanded folder first followed by war file.
Arrays.sort(files, new WarFileComparator());
// filter the list.
Map fileList = new HashMap();
for (File file : files) {
// add folders
if(file.isDirectory()){
fileList.put(file.getName(), file);
} else if(file.getName().endsWith(".war") && !forceWarDeployment){
String name = file.getName().substring(0,file.getName().length()-".war".length());
if(fileList.containsKey(name)){
logger.log(Level.INFO, "War file skipped");
} else {
fileList.put(name, file);
}
} else if(file.getName().endsWith(".war") && forceWarDeployment){
String name = file.getName().substring(0,file.getName().length()-".war".length());
// we must remove the folder from the list if found
if(fileList.containsKey(name)){
fileList.remove(name);
}
fileList.put(name, file);
} else {
fileList.put(file.getName(), file);
}
}
return fileList;
}
public void deployApplications(String locations) throws Exception {
if(locations!=null && locations.length()>0){
String[] location = locations.split(File.pathSeparator);
for (int i = 0; i < location.length; i++) {
deployApplication(location[i]);
}
}
}
private void deployApplication(String location) throws Exception{
// #1
if (location.endsWith(".war")) {
deployWar(location);
return;
}
// #2
if (location.endsWith(".xml")) {
// use the forcedContext if set
deployServlet(location, getForcedContext());
return;
}
// #3-#4
//obtain the list of potential war to deploy
Map fileList = getFile(location);
for (File file : fileList.values()) {
if (file.getName().endsWith(".war")) {
deployWar(file.getPath());
} else {
/*
* we could have these cases
*
* folder contains multiple expanded war or servlet
*
* classes/
* jmaki-comet/
* jmaki-comet2.war
* web.xml
*
* In this case, we have 1 web.xml (servlet), 1 expanded war and 1 war file
*
* The 3 of them will be loaded.
*/
// #4 : this folder in a expanded war
File webxmlFile = new File(location + File.separator + WEB_XML_PATH);
if (webxmlFile.exists()) {
deployExpandedWar(location + File.separator);
} else {
// #2 : this folder contains a servlet
File webxmlFile2 = new File(location + File.separator + "web.xml");
if (webxmlFile2.exists()) {
// this one..see #2
deployServlet(webxmlFile2.getPath());
} else {
// this folder contains multiple war or webapps
File webapp = new File(file.getPath() + File.separator + WEB_XML_PATH);
if (webapp.exists()) {
deployExpandedWar(file.getPath() + File.separator);
}
}
}
}
}
}
/**
* Return the context that will be used to deploy the application
* @param path : file path where the application is
* @return the context
*/
public String getContext(String path) {
if (path == null || path.trim().length()==0) {
return DEFAULT_CONTEXT;
}
// need to replace "/" and "\\" par File.separator
// that will fix the case on Windows when user enter c:/... instead of
// c:\\
//path = path.replaceAll("[/\\\\]+", "\\" + File.separator);
//path = path.replaceAll("\\\\", "\\" + File.separator);
path = path.replaceAll("[/\\\\]+", "\\" + "/");
path = path.replaceAll("\\\\", "\\" + "/");
// remove the trailing File.separator
if(path.endsWith("/") && path.length()>1){
path = path.substring(0,path.length()-1);
}
int lastIndex = path.lastIndexOf("/");
if (lastIndex > 0) {
path = DEFAULT_CONTEXT + path.substring(lastIndex + 1);
} else if(lastIndex==-1){
// need to add the default_context
path = DEFAULT_CONTEXT + path;
}
return path;
}
/**
*
* @param path
* @return
*/
public String getServletPath(String path) {
if (path == null) {
return DEFAULT_CONTEXT;
}
// need to replace "\" and "\\" by "/"
path = path.replaceAll("\\\\", "/");
// the path need to start by "/"
if(!path.startsWith("/")){
path = DEFAULT_CONTEXT + path;
}
// we could have multiples options
// /servlet
// /servlet/
// /servlet/subpath
// /servlet/subpath/
// /servlet/* or /servlet/*.x
// all theses must return /servlet
// remove the trailing "/"
if(path.endsWith("/") && path.length()>1){
path = path.substring(0,path.length()-1);
} else if(!path.endsWith("/")){
// find the last "/"
int index = path.lastIndexOf("/");
// find if we have a wildcard "*" or a extension "."
if(path.lastIndexOf("*")>index || path.lastIndexOf(".")>index){
// do we have something like : /a.cdcdcd or /* or /*.abc
if(index==0){
return "/";
} else {
//remove the urlpattern
if(index> getServletAdapterList(WebApp webApp, String context){
ConcurrentMap> servletAdapterMap = new ConcurrentHashMap>();
// validate if we have servletMapping
if(webApp.getServletMapping()==null || webApp.getServletMapping().isEmpty()){
ServletAdapter sa = new ServletAdapter();
sa.setContextPath(context);
sa.setServletPath("");
List aliasList = new ArrayList();
aliasList.add(DEFAULT_CONTEXT);
servletAdapterMap.put(sa, aliasList);
} else {
for (ServletMapping servletMapping : webApp.getServletMapping()) {
ServletAdapter sa = new ServletAdapter();
List urlPatternList = servletMapping.getUrlPattern();
//TODO support multiple urlPattern ??? for that the SA need to have multiple servletpath ?
// ex : urlPattern = /xxx/1.y
// urlPattern = /xxx/yyy/1.z
// the servlet path will not be the same.. do we create 2 SA ?
// WE WILL GET ONLY THE FIRST urlPattern
String urlPattern = null;
//if empty, assume "/" as context
if (urlPatternList == null || urlPatternList.size() == 0) {
urlPattern = DEFAULT_CONTEXT;
} else {
urlPattern = urlPatternList.get(0);
}
// get the context path. The urlPattern could be "", "/",
// "/bla/xyz/..."
// just to be sure we don't obtain two slash "//"
String servletUrlPattern = null;
if (!urlPattern.startsWith("/")) {
urlPattern = "/" + urlPattern;
}
servletUrlPattern = urlPattern;
if (servletUrlPattern.indexOf("//") > -1) {
servletUrlPattern = servletUrlPattern.replaceAll("//", "/");
}
sa.setContextPath(context);
// be sure not the get the extension mapping
// like /blabla/*.jsp
sa.setServletPath(getServletPath(servletUrlPattern));
// Set the Servlet
setServlet(webApp, sa, servletMapping);
List aliasList = new ArrayList();
aliasList.add(urlPattern);
servletAdapterMap.put(sa, aliasList);
}
}
return servletAdapterMap;
}
public void deploy(String rootFolder, String context, String path) throws Exception {
if (logger.isLoggable(Level.INFO)) {
logger.log(Level.INFO, "Will deploy application path=" + path);
}
// extract the items from the web.xml
WebApp webApp = extractWebxmlInfo(path);
if (webApp == null) {
throw new Exception("invalid");
}
// obtain a servletAdapter list
ConcurrentMap> servletAdapterList = getServletAdapterList(webApp, context);
for (ServletAdapter sa : servletAdapterList.keySet()) {
// set Filters for this context if there are some
setFilters(webApp, sa);
// set Listeners
setListeners(webApp, sa);
//set root Folder
if(rootFolder!=null){
rootFolder = rootFolder.replaceAll("[/\\\\]+", "\\" + "/");
rootFolder = rootFolder.replaceAll("\\\\", "\\" + "/");
sa.setRootFolder(rootFolder);
}
sa.setHandleStaticResources(true);
// create the alias array from the list of urlPattern
String alias[] = getAlias(sa, servletAdapterList.get(sa));
if(alias==null){
alias = new String[]{DEFAULT_CONTEXT};
}
if (logger.isLoggable(Level.FINEST)) {
logger.log(Level.FINEST, "sa context=" + sa.getContextPath());
logger.log(Level.FINEST, "sa servletPath=" + sa.getServletPath());
StringBuffer sb = new StringBuffer();
sb.append("[");
for (String item : alias) {
sb.append(item).append(",");
}
sb.deleteCharAt(sb.length()-1);
sb.append("]");
logger.log(Level.FINEST, "sa alias=" + sb.toString());
logger.log(Level.FINEST, "sa rootFolder=" + sa.getRootFolder());
}
SelectorThread.setWebAppRootPath(rootFolder);
// keep trace of deployed application
deployedApplicationList.add(context);
ws.addGrizzlyAdapter(sa, alias);
}
if (logger.isLoggable(Level.INFO)) {
logger.log(Level.INFO, "deployed application path=" + path);
}
}
/**
*
* @param sa ServletAdapter
* @param aliases contains the list of UrlPattern for this ServletAdapter
* @return the alias list for this ServletAdapter
*/
public String[] getAlias(ServletAdapter sa, Collection aliases){
if(sa==null || aliases==null){
return null;
}
List aliasList = new ArrayList();
for (String urlPattern : aliases) {
String mapping = "";
if(!sa.getServletPath().equals(urlPattern)){
mapping = urlPattern.substring(urlPattern.indexOf(sa.getServletPath()));
}
// the alias is the context + servletPath + mapping
String aliasTmp = sa.getContextPath() + sa.getServletPath() + mapping;
if (aliasTmp.indexOf("//") > -1) {
aliasTmp = aliasTmp.replaceAll("//", "/");
}
aliasList.add(aliasTmp);
/*
// if the urlPattern is "/", we want to map the default "" too
if(urlPattern.equals("/")){
aliasList.add("");
}
*/
}
String[] array = new String[aliasList.size()];
return aliasList.toArray(array);
}
protected void setLocations(String filename) {
locations = filename;
}
protected String getLocations() {
return locations;
}
protected void setPort(int port) {
this.port = port;
}
protected int getPort() {
return port;
}
protected String getLibraryPath() {
return libraryPath;
}
protected void setLibraryPath(String path) {
this.libraryPath = path;
}
public boolean getCometEnabled() {
return cometEnabled;
}
public void setCometEnabled(boolean enabled) {
this.cometEnabled = enabled;
}
public boolean getAjpEnabled() {
return ajpEnabled;
}
public void setAjpEnabled(boolean enabled) {
this.ajpEnabled = enabled;
}
public boolean getForceWarDeployment() {
return forceWarDeployment;
}
public void setForceWarDeployment(boolean forceWarDeployment) {
this.forceWarDeployment = forceWarDeployment;
}
public List getDeployedApplicationList() {
return deployedApplicationList;
}
public void setDeployedApplicationList(List deployedApplicationList) {
this.deployedApplicationList = deployedApplicationList;
}
public void printHelpAndExit() {
System.err.println("Usage: " + GrizzlyWebServerDeployer.class.getCanonicalName());
System.err.println();
System.err.println(" -p, --port=port Runs Servlet on the specified port.");
System.err.println(" Default: 8080");
System.err.println(" -a, --application=application path The Servlet folder or jar or war location. Can append multiple application. Separator = File.pathSeparator");
System.err.println(" -c, --context=context The context that will be use for servlet or warfile");
System.err.println(" --dontstart= Default: false, Will not start the server until the start method is called. Useful for Unit test");
System.err.println(" --libraryPath Add a libraries folder to the classpath. Can append multiple folder. Separator = File.pathSeparator");
System.err.println(" --cometEnabled Will start the AsyncFilter for Comet");
System.err.println(" --forceWarDeployment Will force deployment of a war file over a expanded folder");
System.err.println(" --ajpEnabled Will enabled mod_jk");
System.err.println(" -h, --help Show this help message.");
System.exit(1);
}
public boolean parseOptions(String[] args) {
// parse options
for (int i = 0; i < args.length; i++) {
String arg = args[i];
if ("-h".equals(arg) || "--help".equals(arg)) {
printHelpAndExit();
} else if ("-a".equals(arg)) {
i++;
if(i servletList = webApp.getServlet();
//we need to get the servlet according to the servletMapping
for (com.sun.grizzly.http.webxml.schema.Servlet servletItem : servletList) {
if (servletItem.getServletName().equalsIgnoreCase(servletMapping.getServletName())) {
Servlet servlet = (Servlet) ClassLoaderUtil.load(servletItem.getServletClass());
sa.setServletInstance(servlet);
List initParamsList = servletItem.getInitParam();
if (initParamsList != null && initParamsList.size() > 0) {
for (InitParam element : initParamsList) {
sa.addInitParameter(element.getParamName(), element.getParamValue());
}
}
break;
}
}
}
protected void setListeners(WebApp webApp, ServletAdapter sa) {
// Add the Listener
List listeners = webApp.getListener();
if (listeners != null) {
for (Listener element : listeners) {
sa.addServletListener(element.getListenerClass());
}
}
}
protected void setFilters(WebApp webApp, ServletAdapter sa) {
// Add the Filters
List filterList = webApp.getFilter();
List filterMappingList = webApp.getFilterMapping();
if (filterList != null && filterList.size() > 0) {
for (com.sun.grizzly.http.webxml.schema.Filter filterItem : filterList) {
// we had the filter if the url-pattern is for this context
// we need to get the right filter-mapping form the name
for (FilterMapping filterMapping : filterMappingList) {
//we need to find in the filterMapping is for this filter
if (filterItem.getFilterName().equalsIgnoreCase(filterMapping.getFilterName())) {
Filter filter = (Filter) ClassLoaderUtil.load(filterItem.getFilterClass());
// initParams
List initParamList = filterItem.getInitParam();
Map initParamsMap = new HashMap();
if (initParamList != null) {
for (InitParam param : initParamList) {
initParamsMap.put(param.getParamName(), param.getParamValue());
}
}
sa.addFilter(filter, filterItem.getFilterName(), initParamsMap);
}
}
}
}
}
protected Map> getItemMap(List © 2015 - 2025 Weber Informatics LLC | Privacy Policy