Index: modules/utils/src/main/java/com/sun/grizzly/util/ClassLoaderUtil.java =================================================================== --- modules/utils/src/main/java/com/sun/grizzly/util/ClassLoaderUtil.java (.../trunk/code) (revision 3643) +++ modules/utils/src/main/java/com/sun/grizzly/util/ClassLoaderUtil.java (.../branches/deployer-refactoring) (revision 3643) @@ -40,7 +40,6 @@ 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.logging.Level; @@ -56,31 +55,27 @@ * Create a class loader that can load classes from the specified * file directory. The file directory must contains .jar ot .zip * - * @param file a directory - * @param ClassLoader the parent classloader, or null if none. + * @param libDir a directory + * @param cl the parent classloader, or null if none. * @return A Classloader that can load classes from a directory that * contains jar and zip files. + * @throws java.io.IOException I/O fail + * @deprecated removal candidate, never used */ - public final static ClassLoader createClassloader(File libDir, ClassLoader cl) + public static ClassLoader createClassloader(File libDir, ClassLoader cl) throws IOException{ URLClassLoader urlClassloader = null; if (libDir.exists()){ if (libDir.isDirectory()){ String[] jars = libDir.list(new FilenameFilter() { public boolean accept(File dir, String name) { - if (name.endsWith(".jar") || name.endsWith(".zip")){ - return true; - } else { - return false; - } - + return name.endsWith(".jar") || name.endsWith(".zip"); } }); URL[] urls = new URL[jars.length]; for (int i=0; i < jars.length; i++){ String path = new File(libDir.getName() - + File.separator + jars[i]).getCanonicalFile().toURL() - .toString(); + + File.separator + jars[i]).getCanonicalFile().toURI().toURL().toString(); urls[i] = new URL(path); } urlClassloader = new URLClassLoader(urls,cl); @@ -90,17 +85,18 @@ } /** - * Construct a {@link URLClassloader} based on a canonial file location. + * Construct a {@link URLClassLoader} based on a canonial file location. * @param dirPath a canonial path location * @return a {@link URLClassLoader} + * @throws java.io.IOException I/O + * @throws java.net.MalformedURLException Invalid URL */ - public static URLClassLoader createURLClassLoader(String dirPath) throws MalformedURLException - , IOException{ + public static URLClassLoader createURLClassLoader(String dirPath) throws IOException{ String path; - File file = null; - URL appRoot = null; - URL classesURL = null; + File file; + URL appRoot; + URL classesURL; if (!dirPath.endsWith(File.separator)){ dirPath += File.separator; @@ -120,10 +116,10 @@ appRoot = new URL("file://" + path); } - String absolutePath = new File(path).getAbsolutePath(); - URL[] urls = null; + String absolutePath = new File(path).getAbsolutePath(); + URL[] urls; File libFiles = new File(absolutePath + File.separator + "WEB-INF"+ File.separator + "lib"); - int arraySize = (appRoot == null ? 1:2); + int arraySize = 2; //Must be a better way because that sucks! String separator = (System.getProperty("os.name") @@ -140,9 +136,7 @@ urls[urls.length -1] = classesURL; urls[urls.length -2] = appRoot; - URLClassLoader urlClassloader = new URLClassLoader(urls, - Thread.currentThread().getContextClassLoader()); - return urlClassloader; + return new URLClassLoader(urls, Thread.currentThread().getContextClassLoader()); } /** @@ -155,13 +149,13 @@ } /** - * Load a class using the provided {@link Classloader} + * Load a class using the provided {@link ClassLoader} * @param clazzName The name of the class you want to load. * @param classLoader A classloader to use for loading a class. * @return an instance of clazzname */ public static Object load(String clazzName, ClassLoader classLoader) { - Class className = null; + Class className; try { className = Class.forName(clazzName, true, classLoader); return className.newInstance(); Index: modules/http-servlet-deployer/src/main/java/com/sun/grizzly/http/servlet/deployer/WebAppAdapter.java =================================================================== --- modules/http-servlet-deployer/src/main/java/com/sun/grizzly/http/servlet/deployer/WebAppAdapter.java (.../trunk/code) (revision 0) +++ modules/http-servlet-deployer/src/main/java/com/sun/grizzly/http/servlet/deployer/WebAppAdapter.java (.../branches/deployer-refactoring) (revision 3643) @@ -0,0 +1,453 @@ +/** + * + * 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 com.sun.grizzly.http.servlet.ServletAdapter; +import com.sun.grizzly.http.webxml.schema.*; +import com.sun.grizzly.http.embed.GrizzlyWebServer; +import com.sun.grizzly.tcp.http11.GrizzlyRequest; +import com.sun.grizzly.tcp.http11.GrizzlyResponse; +import com.sun.grizzly.util.ClassLoaderUtil; + +import javax.servlet.Servlet; +import javax.servlet.Filter; +import java.net.URLClassLoader; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * {@link com.sun.grizzly.http.webxml.schema.WebApp} Adapter. + * + * @author Hubert Iwaniuk + * @since Aug 25, 2009 + */ +public class WebAppAdapter extends ServletAdapter { + private static Logger logger = Logger.getLogger("WebAppAdapter"); + private static final String EMPTY_SERVLET_PATH = ""; + + private static final String ROOT = "/"; + + private WebApp webApp; + private ClassLoader webAppCL; + private GrizzlyWebServer gws; + private String root; + private String context; + + /** + * Default constructor, takes care of setting up adapter. + * + * @param gws Grizzly Web Server to register {@link ServletAdapter}s. + * @param root Root folder, for serving static resources? + * @param context Context to be deployed to. + * @param webApp Web application to be run by this adapter. + * @param webAppCL Web application class loader. + * @param webdefault Default web application. + */ + public WebAppAdapter(GrizzlyWebServer gws, String root, String context, final WebApp webApp, URLClassLoader webAppCL, WebApp webdefault) { + this.gws = gws; + this.root = root; + this.context = context; + if (webdefault != null) { + this.webApp = webApp.mergeWith(webdefault); + } else { + this.webApp = webApp; + } + this.webAppCL = webAppCL; + ClassLoader prevCL = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(webAppCL); + try { + initialize(); + } finally { + Thread.currentThread().setContextClassLoader(prevCL); + } + } + + private void initialize() { + + boolean blankContextServletPathFound = false; + boolean defaultContextServletPathFound = false; + + List aliasesUsed = new ArrayList(); + + for (Map.Entry> adapterAliases : + getServletAdaptersToAlises(webApp, context).entrySet()) { + ServletAdapter sa = adapterAliases.getKey(); + sa.setClassLoader(webAppCL); + + // set Filters for this context if there are some + setFilters(webApp, sa); + + // set Listeners + setListeners(webApp, sa); + + //set root Folder + sa.setRootFolder(root); + + // create the alias array from the list of urlPattern + String alias[] = getAlias(sa, adapterAliases.getValue()); + + // need to be disabled for JSP + sa.setHandleStaticResources(false); + + // enabled it if not / or /* + for (String item : alias) { + if (item.endsWith(ROOT) || item.endsWith("/*")) { + sa.setHandleStaticResources(true); + } + } + + if (logger.isLoggable(Level.FINEST)) { + logServletAdapterConfigurationWithAliases(sa, alias); + } + + // keep trace of mapping + aliasesUsed.addAll(Arrays.asList(alias)); + + gws.addGrizzlyAdapter(sa, alias); + + if (ROOT.equals(sa.getServletPath())) { + defaultContextServletPathFound = true; + } + + if (EMPTY_SERVLET_PATH.equals(sa.getServletPath())) { + blankContextServletPathFound = true; + } + } + + // we need one servlet that will handle "/" + if (!defaultContextServletPathFound) { + logger.log(Level.FINEST, "Adding a ServletAdapter to handle / path"); + createAndInstallServletAdapter(root, context, ROOT); + } + + // pour les jsp dans le root du context + if (!blankContextServletPathFound && !aliasesUsed.contains(context + ROOT)) { + logger.log(Level.FINEST, "Adding a ServletAdapter to handle root path"); + createAndInstallServletAdapter(root, context, EMPTY_SERVLET_PATH); + } + } + + private void createAndInstallServletAdapter( + final String rootFolder, final String context, final String tmpPath) { + ServletAdapter sa = new ServletAdapter(); + + sa.setContextPath(context); + sa.setServletPath(tmpPath); + sa.setHandleStaticResources(true); + sa.setRootFolder(rootFolder); + + logServletAdapterConfiguration(context, sa); + + gws.addGrizzlyAdapter(sa, new String[]{context + ROOT}); + } + + private static void logServletAdapterConfiguration(final String ctx, final ServletAdapter sa) { + if (logger.isLoggable(Level.FINEST)) { + WebAppAdapter.debugServletAdapterConfiguration(sa, ctx + ROOT); + } + } + + public void service(final GrizzlyRequest request, final GrizzlyResponse response) { + ClassLoader prevCL = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(webAppCL); + try { + // TODO here we should take care of welcome-file + } finally { + Thread.currentThread().setContextClassLoader(prevCL); + } + } + + /** + * @param webApp Contains the info about the web.xml + * @param context context of the application + * @return a list of ServletAdapter with the UrlPattern for each Servlet. + */ + static Map> getServletAdaptersToAlises(WebApp webApp, String context) { + + Map> servletAdapterMap; + + if (webApp == null || webApp.getServletMapping() == null || webApp.getServletMapping().isEmpty()) { + ServletAdapter sa = new ServletAdapter(); + + sa.setContextPath(context); + sa.setServletPath(EMPTY_SERVLET_PATH); + + servletAdapterMap = new HashMap>(1); + servletAdapterMap.put(sa, Arrays.asList(ROOT)); + } else { + // if we have servletMapping + + final List mappings = webApp.getServletMapping(); + servletAdapterMap = new HashMap>(mappings.size()); + for (ServletMapping servletMapping : mappings) { + + 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; + //if empty, assume "/" as context + if (urlPatternList == null || urlPatternList.isEmpty()) { + urlPattern = ROOT; + } 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 "//" + + if (!urlPattern.startsWith(ROOT)) { + urlPattern = String.format("%s%s", ROOT, urlPattern); + } + String servletUrlPattern = urlPattern; + + if (servletUrlPattern.indexOf("//") > -1) { + servletUrlPattern = servletUrlPattern.replaceAll("//", ROOT); + } + + ServletAdapter sa = createServletAdapter(context, servletUrlPattern); + + // Set the Servlet + setServlet(webApp, sa, servletMapping); + + servletAdapterMap.put(sa, Arrays.asList(urlPattern)); + } + } + + return servletAdapterMap; + } + + protected static void setServlet(WebApp webApp, ServletAdapter sa, ServletMapping servletMapping) { + //we need to get the servlet according to the servletMapping + for (com.sun.grizzly.http.webxml.schema.Servlet servletItem : webApp.getServlet()) { + + if (servletItem.getServletName().equalsIgnoreCase(servletMapping.getServletName())) { + sa.setServletInstance((Servlet) ClassLoaderUtil.load(servletItem.getServletClass())); + + List initParamsList = servletItem.getInitParam(); + + if (initParamsList != null && !initParamsList.isEmpty()) { + for (InitParam element : initParamsList) { + sa.addInitParameter(element.getParamName(), element.getParamValue()); + } + } + break; + } + } + } + + /** + * @param path Path to convert. + * @return Converted path. + */ + public static String getServletPath(String path) { + + String result; + if (path == null) { + result = ROOT; + } else { + + // need to replace "\" and "\\" by "/" + result = path.replaceAll("\\\\", ROOT); + + // the path need to start by "/" + if (!result.startsWith(ROOT)) { + result = ROOT + result; + } + + // we could have multiples options + // /servlet + // /servlet/ + // /servlet/subpath + // /servlet/subpath/ + // /servlet/* or /servlet/*.x + // all theses must return /servlet + + // remove the trailing "/" + if (result.endsWith(ROOT) && result.length() > 1) { + result = result.substring(0, result.length() - 1); + } else if (!result.endsWith(ROOT)) { + + // find the last "/" + int index = result.lastIndexOf(ROOT); + + // find if we have a wildcard "*" or a extension "." + if (result.lastIndexOf('*') > index || result.lastIndexOf('.') > index) { + + // do we have something like : /a.cdcdcd or /* or /*.abc + if (index == 0) { + result = ROOT; + } else if (index > 0) { + //remove the urlpattern + if (index < result.length()) { + result = result.substring(0, index); + } + } + } + } + } + return result; + } + + static ServletAdapter createServletAdapter( + final String context, final String servletUrlPattern) { + ServletAdapter sa = new ServletAdapter(); + sa.setContextPath(context); + + // be sure not the get the extension mapping + // like /blabla/*.jsp + sa.setServletPath(getServletPath(servletUrlPattern)); + return sa; + } + + protected static void setFilters(WebApp webApp, ServletAdapter sa) { + + if (webApp == null || sa == null) { + return; + } + + // Add the Filters + List filterList = webApp.getFilter(); + + List filterMappingList = webApp.getFilterMapping(); + + if (filterList != null && !filterList.isEmpty()) { + 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 static void setListeners(WebApp webApp, ServletAdapter sa) { + if (webApp == null || sa == null) { + return; + } + + // Add the Listener + List listeners = webApp.getListener(); + + if (listeners != null) { + for (Listener element : listeners) { + sa.addServletListener(element.getListenerClass()); + } + } + } + + /** + * @param sa ServletAdapter + * @param aliases contains the list of UrlPattern for this ServletAdapter + * @return the alias list for this ServletAdapter + */ + public static String[] getAlias(ServletAdapter sa, Collection aliases) { + + List aliasList; + if (sa == null || aliases == null) { + // Default context + aliasList = Arrays.asList(ROOT); + } else { + + aliasList = new ArrayList(aliases.size()); + for (String urlPattern : aliases) { + + String mapping = EMPTY_SERVLET_PATH; + + if (!sa.getServletPath().equals(urlPattern) && urlPattern.indexOf(sa.getServletPath()) > -1) { + mapping = urlPattern.substring(urlPattern.indexOf(sa.getServletPath()) + sa.getServletPath().length()); + } + + // the alias is the context + servletPath + mapping + String aliasTmp = String.format("%s%s%s", sa.getContextPath(), sa.getServletPath(), mapping); + + if (aliasTmp.indexOf("//") > -1) { + aliasTmp = aliasTmp.replaceAll("//", ROOT); + } + aliasList.add(aliasTmp); + } + } + return aliasList.toArray(new String[aliasList.size()]); + } + + static void logServletAdapterConfigurationWithAliases( + final ServletAdapter sa, final String[] aliases) { + StringBuilder sb = new StringBuilder(64); + sb.append('['); + for (String item : aliases) { + sb.append(item).append(','); + } + sb.deleteCharAt(sb.length() - 1); + sb.append(']'); + debugServletAdapterConfiguration(sa, sb.toString()); + } + + static void debugServletAdapterConfiguration( + final ServletAdapter sa, final String alias) { + logger.log(Level.FINEST, "sa context=" + sa.getContextPath()); + logger.log(Level.FINEST, "sa servletPath=" + sa.getServletPath()); + logger.log(Level.FINEST, "sa alias=" + alias); + logger.log(Level.FINEST, "sa rootFolder=" + sa.getRootFolder()); + } +} Index: modules/http-servlet-deployer/src/main/java/com/sun/grizzly/http/webxml/schema/WebApp.java =================================================================== --- modules/http-servlet-deployer/src/main/java/com/sun/grizzly/http/webxml/schema/WebApp.java (.../trunk/code) (revision 3643) +++ modules/http-servlet-deployer/src/main/java/com/sun/grizzly/http/webxml/schema/WebApp.java (.../branches/deployer-refactoring) (revision 3643) @@ -36,6 +36,7 @@ package com.sun.grizzly.http.webxml.schema; import java.util.List; +import java.util.ArrayList; /** * This class represent a web.xml. @@ -66,38 +67,38 @@ */ public class WebApp { - public List icon; - public List displayName; - public List description; + public List icon = new ArrayList(0); + public List displayName = new ArrayList(0); + public List description = new ArrayList(0); public boolean distributable; - public List contextParam; - public List filter; - public List filterMapping; - public List listener; - public List servlet; - public List servletMapping; - public List sessionConfig; - public List mimeMapping; - public List welcomeFileList; - public List errorPage; - public List taglib; - public List resourceEnvRef; - public List resourceRef; - public List securityConstraint; - public List loginConfig; - public List securityRole; - public List envEntry; - public List ejbRef; - public List ejbLocalRef; - public List jspConfig; - public List serviceRef; - public List messageDestination; - public List messageDestinationRef; - public List persistenceContextRef; - public List persistenceUnitRef; - public List postConstruct; - public List preDestroy; - public List localeEncodingMappingList; + public List contextParam = new ArrayList(0); + public List filter = new ArrayList(0); + public List filterMapping = new ArrayList(0); + public List listener = new ArrayList(0); + public List servlet = new ArrayList(0); + public List servletMapping = new ArrayList(0); + public List sessionConfig = new ArrayList(0); + public List mimeMapping = new ArrayList(0); + public List welcomeFileList = new ArrayList(0); + public List errorPage = new ArrayList(0); + public List taglib = new ArrayList(0); + public List resourceEnvRef = new ArrayList(0); + public List resourceRef = new ArrayList(0); + public List securityConstraint = new ArrayList(0); + public List loginConfig = new ArrayList(0); + public List securityRole = new ArrayList(0); + public List envEntry = new ArrayList(0); + public List ejbRef = new ArrayList(0); + public List ejbLocalRef = new ArrayList(0); + public List jspConfig = new ArrayList(0); + public List serviceRef = new ArrayList(0); + public List messageDestination = new ArrayList(0); + public List messageDestinationRef = new ArrayList(0); + public List persistenceContextRef = new ArrayList(0); + public List persistenceUnitRef = new ArrayList(0); + public List postConstruct = new ArrayList(0); + public List preDestroy = new ArrayList(0); + public List localeEncodingMappingList = new ArrayList(0); /** * @@ -110,7 +111,9 @@ } public void setIcon(List icon) { - this.icon = icon; + if (icon != null) { + this.icon = icon; + } } /** @@ -121,7 +124,9 @@ } public void setDisplayName(List displayName) { - this.displayName = displayName; + if (displayName != null) { + this.displayName = displayName; + } } /** @@ -132,7 +137,9 @@ } public void setDescription(List description) { - this.description = description; + if (description != null) { + this.description = description; + } } /** @@ -158,7 +165,9 @@ } public void setServlet(List servlet) { - this.servlet = servlet; + if (servlet != null) { + this.servlet = servlet; + } } /** @@ -176,7 +185,9 @@ } public void setFilter(List filter) { - this.filter = filter; + if (filter != null) { + this.filter = filter; + } } /** @@ -191,7 +202,9 @@ } public void setContextParam(List contextParam) { - this.contextParam = contextParam; + if (contextParam != null) { + this.contextParam = contextParam; + } } /** @@ -214,7 +227,9 @@ } public void setEjbLocalRef(List ejbLocalRef) { - this.ejbLocalRef = ejbLocalRef; + if (ejbLocalRef != null) { + this.ejbLocalRef = ejbLocalRef; + } } /** @@ -237,7 +252,9 @@ } public void setEjbRef(List ejbRef) { - this.ejbRef = ejbRef; + if (ejbRef != null) { + this.ejbRef = ejbRef; + } } /** @@ -258,7 +275,9 @@ } public void setEnvEntry(List envEntry) { - this.envEntry = envEntry; + if (envEntry != null) { + this.envEntry = envEntry; + } } /** @@ -273,7 +292,9 @@ } public void setErrorPage(List errorPage) { - this.errorPage = errorPage; + if (errorPage != null) { + this.errorPage = errorPage; + } } /** @@ -293,7 +314,9 @@ } public void setFilterMapping(List filterMapping) { - this.filterMapping = filterMapping; + if (filterMapping != null) { + this.filterMapping = filterMapping; + } } /** @@ -312,7 +335,9 @@ } public void setListener(List listener) { - this.listener = listener; + if (listener != null) { + this.listener = listener; + } } /** @@ -330,7 +355,9 @@ } public void setLoginConfig(List loginConfig) { - this.loginConfig = loginConfig; + if (loginConfig != null) { + this.loginConfig = loginConfig; + } } /** @@ -344,7 +371,9 @@ } public void setMimeMapping(List mimeMapping) { - this.mimeMapping = mimeMapping; + if (mimeMapping != null) { + this.mimeMapping = mimeMapping; + } } /** @@ -364,7 +393,9 @@ } public void setResourceEnvRef(List resourceEnvRef) { - this.resourceEnvRef = resourceEnvRef; + if (resourceEnvRef != null) { + this.resourceEnvRef = resourceEnvRef; + } } /** @@ -387,7 +418,9 @@ } public void setSecurityConstraint(List securityConstraint) { - this.securityConstraint = securityConstraint; + if (securityConstraint != null) { + this.securityConstraint = securityConstraint; + } } /** @@ -401,7 +434,9 @@ } public void setServletMapping(List servletMapping) { - this.servletMapping = servletMapping; + if (servletMapping != null) { + this.servletMapping = servletMapping; + } } /** @@ -423,7 +458,9 @@ } public void setSessionConfig(List sessionConfig) { - this.sessionConfig = sessionConfig; + if (sessionConfig != null) { + this.sessionConfig = sessionConfig; + } } /** @@ -437,7 +474,9 @@ } public void setTaglib(List taglib) { - this.taglib = taglib; + if (taglib != null) { + this.taglib = taglib; + } } /** @@ -451,7 +490,9 @@ } public void setSecurityRole(List securityRole) { - this.securityRole = securityRole; + if (securityRole != null) { + this.securityRole = securityRole; + } } /** @@ -473,7 +514,9 @@ } public void setResourceRef(List resourceRef) { - this.resourceRef = resourceRef; + if (resourceRef != null) { + this.resourceRef = resourceRef; + } } /** @@ -487,7 +530,9 @@ } public void setWelcomeFileList(List welcomeFileList) { - this.welcomeFileList = welcomeFileList; + if (welcomeFileList != null) { + this.welcomeFileList = welcomeFileList; + } } /** @@ -523,7 +568,9 @@ } public void setJspConfig(List jspConfig) { - this.jspConfig = jspConfig; + if (jspConfig != null) { + this.jspConfig = jspConfig; + } } /** @@ -600,7 +647,9 @@ } public void setServiceRef(List serviceRef) { - this.serviceRef = serviceRef; + if (serviceRef != null) { + this.serviceRef = serviceRef; + } } /** @@ -620,7 +669,9 @@ } public void setMessageDestination(List messageDestination) { - this.messageDestination = messageDestination; + if (messageDestination != null) { + this.messageDestination = messageDestination; + } } /** @@ -642,7 +693,9 @@ } public void setMessageDestinationRef(List messageDestinationRef) { - this.messageDestinationRef = messageDestinationRef; + if (messageDestinationRef != null) { + this.messageDestinationRef = messageDestinationRef; + } } /** @@ -667,7 +720,9 @@ } public void setPersistenceContextRef(List persistenceContextRef) { - this.persistenceContextRef = persistenceContextRef; + if (persistenceContextRef != null) { + this.persistenceContextRef = persistenceContextRef; + } } /** @@ -687,7 +742,9 @@ } public void setPersistenceUnitRef(List persistenceUnitRef) { - this.persistenceUnitRef = persistenceUnitRef; + if (persistenceUnitRef != null) { + this.persistenceUnitRef = persistenceUnitRef; + } } /** @@ -701,7 +758,9 @@ } public void setPostConstruct(List postConstruct) { - this.postConstruct = postConstruct; + if (postConstruct != null) { + this.postConstruct = postConstruct; + } } /** @@ -715,7 +774,9 @@ } public void setPreDestroy(List preDestroy) { - this.preDestroy = preDestroy; + if (preDestroy != null) { + this.preDestroy = preDestroy; + } } /** @@ -731,7 +792,9 @@ } public void setLocaleEncodingMappingList(List localeEncodingMappingList) { - this.localeEncodingMappingList = localeEncodingMappingList; + if (localeEncodingMappingList != null) { + this.localeEncodingMappingList = localeEncodingMappingList; + } } public String toString() { @@ -994,4 +1057,38 @@ return buffer.toString(); } + public WebApp mergeWith(WebApp with) { + this.contextParam.addAll(with.contextParam); + this.description.addAll(with.description); + this.displayName.addAll(with.displayName); + this.ejbLocalRef.addAll(with.ejbLocalRef); + this.ejbRef.addAll(with.ejbRef); + this.envEntry.addAll(with.envEntry); + this.errorPage.addAll(with.errorPage); + this.filter.addAll(with.filter); + this.filterMapping.addAll(with.filterMapping); + this.icon.addAll(with.icon); + this.jspConfig.addAll(with.jspConfig); + this.listener.addAll(with.listener); + this.localeEncodingMappingList.addAll(with.localeEncodingMappingList); + this.loginConfig.addAll(with.loginConfig); + this.messageDestination.addAll(with.messageDestination); + this.messageDestinationRef.addAll(with.messageDestinationRef); + this.mimeMapping.addAll(with.mimeMapping); + this.persistenceContextRef.addAll(with.persistenceContextRef); + this.persistenceUnitRef.addAll(with.persistenceUnitRef); + this.postConstruct.addAll(with.postConstruct); + this.preDestroy.addAll(with.preDestroy); + this.resourceEnvRef.addAll(with.resourceEnvRef); + this.resourceRef.addAll(with.resourceRef); + this.securityConstraint.addAll(with.securityConstraint); + this.securityRole.addAll(with.securityRole); + this.serviceRef.addAll(with.serviceRef); + this.servlet.addAll(with.servlet); + this.servletMapping.addAll(with.servletMapping); + this.sessionConfig.addAll(with.sessionConfig); + this.taglib.addAll(with.taglib); + this.welcomeFileList.addAll(with.welcomeFileList); + return this; + } } Index: modules/http-servlet-deployer/src/main/java/com/sun/grizzly/http/webxml/WebappLoader.java =================================================================== --- modules/http-servlet-deployer/src/main/java/com/sun/grizzly/http/webxml/WebappLoader.java (.../trunk/code) (revision 3643) +++ modules/http-servlet-deployer/src/main/java/com/sun/grizzly/http/webxml/WebappLoader.java (.../branches/deployer-refactoring) (revision 3643) @@ -126,7 +126,7 @@ * @return the WebApp loaded * @throws Exception any exceptions will be thrown here if there is a problem parsing the file */ - public WebApp load(String webxml) throws Exception { + public static WebApp load(String webxml) throws Exception { // load the xml file to get it's schema version WebXmlHelper helper = new WebXmlHelper(); @@ -143,10 +143,8 @@ if(logger.isLoggable(Level.FINEST)){ logger.log(Level.FINEST, "Version found=" + schemaVersion); } - - WebApp webapp = extractWebXmlInfo(schemaVersion, webxml); - - return webapp; + + return extractWebXmlInfo(schemaVersion, webxml); } /** @@ -157,14 +155,12 @@ * @throws Exception */ @SuppressWarnings("unchecked") - protected WebApp extractWebXmlInfo(String schemaVersion, String webxml) throws Exception { - - Class clazz = Class.forName(webAppMap.get(schemaVersion)); - IJAXBWebXmlParser parser = (IJAXBWebXmlParser)clazz.newInstance(); - - WebApp webapp = parser.parse(webxml); - - return webapp; + protected static WebApp extractWebXmlInfo(String schemaVersion, String webxml) throws Exception { + + IJAXBWebXmlParser parser = (IJAXBWebXmlParser) + ((Class) Class.forName(webAppMap.get(schemaVersion))).newInstance(); + + return parser.parse(webxml); } Index: modules/bundles/http-servlet-deployer/src/test/java/com/sun/grizzly/http/servlet/deployer/DeployerTest.java =================================================================== --- modules/bundles/http-servlet-deployer/src/test/java/com/sun/grizzly/http/servlet/deployer/DeployerTest.java (.../trunk/code) (revision 3643) +++ modules/bundles/http-servlet-deployer/src/test/java/com/sun/grizzly/http/servlet/deployer/DeployerTest.java (.../branches/deployer-refactoring) (revision 3643) @@ -4,8 +4,8 @@ public class DeployerTest extends TestCase { - protected GrizzlyWebServerDeployer deployer = null; - + private GrizzlyWebServerDeployer deployer = null; + protected void setUp() throws Exception { deployer = new GrizzlyWebServerDeployer(); } @@ -13,55 +13,55 @@ /** * Extract the servlet path from a URL * - * @throws Exception + * @throws Exception Duh! */ public void testGetServletPath() throws Exception { // no context and no servlet - assertEquals("/", deployer.getServletPath("")); + assertEquals("/", WebAppAdapter.getServletPath("")); // no context and root servlet - assertEquals("/", deployer.getServletPath("/")); + assertEquals("/", WebAppAdapter.getServletPath("/")); // no context and root servlet with wildcard mapping - assertEquals("/", deployer.getServletPath("/*")); + assertEquals("/", WebAppAdapter.getServletPath("/*")); // with context - assertEquals("/servlet1", deployer.getServletPath("/servlet1/")); + assertEquals("/servlet1", WebAppAdapter.getServletPath("/servlet1/")); // with context and urlPattern - assertEquals("/servlet1", deployer.getServletPath("/servlet1/*.jsp")); + assertEquals("/servlet1", WebAppAdapter.getServletPath("/servlet1/*.jsp")); // with context and urlPattern - assertEquals("/servlet1", deployer.getServletPath("/servlet1/a.jsp")); + assertEquals("/servlet1", WebAppAdapter.getServletPath("/servlet1/a.jsp")); // with context and urlPattern - assertEquals("/servlet1", deployer.getServletPath("/servlet1/.jsp")); + assertEquals("/servlet1", WebAppAdapter.getServletPath("/servlet1/.jsp")); // with context and urlPattern - assertEquals("/servlet1", deployer.getServletPath("/servlet1/*")); + assertEquals("/servlet1", WebAppAdapter.getServletPath("/servlet1/*")); //with context and multiple paths - assertEquals("/servlet1/subpath", deployer.getServletPath("/servlet1/subpath/")); + assertEquals("/servlet1/subpath", WebAppAdapter.getServletPath("/servlet1/subpath/")); //with context and multiple paths - assertEquals("/servlet1/subpath", deployer.getServletPath("/servlet1/subpath")); + assertEquals("/servlet1/subpath", WebAppAdapter.getServletPath("/servlet1/subpath")); //with context and multiple paths and wildcard - assertEquals("/servlet1/subpath", deployer.getServletPath("/servlet1/subpath/*")); + assertEquals("/servlet1/subpath", WebAppAdapter.getServletPath("/servlet1/subpath/*")); //with context and multiple paths and wildcard - assertEquals("/servlet1/subpath/*/abc", deployer.getServletPath("/servlet1/subpath/*/abc")); + assertEquals("/servlet1/subpath/*/abc", WebAppAdapter.getServletPath("/servlet1/subpath/*/abc")); //with context and multiple paths and wildcard - assertEquals("/servlet1/subpath/*/abc", deployer.getServletPath("/servlet1/subpath/*/abc/1.zxy")); + assertEquals("/servlet1/subpath/*/abc", WebAppAdapter.getServletPath("/servlet1/subpath/*/abc/1.zxy")); } /** * Extract the servlet path from a URL * - * @throws Exception + * @throws Exception Duh! */ public void testGetContextPath() throws Exception { // no context Index: modules/bundles/http-servlet-deployer/src/main/java/com/sun/grizzly/http/servlet/deployer/GrizzlyWebServerDeployer.java =================================================================== --- modules/bundles/http-servlet-deployer/src/main/java/com/sun/grizzly/http/servlet/deployer/GrizzlyWebServerDeployer.java (.../trunk/code) (revision 3643) +++ modules/bundles/http-servlet-deployer/src/main/java/com/sun/grizzly/http/servlet/deployer/GrizzlyWebServerDeployer.java (.../branches/deployer-refactoring) (revision 3643) @@ -35,44 +35,28 @@ */ 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.servlet.deployer.conf.ConfigurationParser; +import com.sun.grizzly.http.servlet.deployer.conf.DeployerConfiguration; 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.http.webxml.schema.*; import com.sun.grizzly.util.ExpandJar; +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.*; +import java.util.logging.Level; +import java.util.logging.Logger; + /* * We have 4 cases : * @@ -85,917 +69,346 @@ */ 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 autodeployFolder; - 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; + private static Logger logger = Logger.getLogger("GrizzlyWebServerDeployerLogger"); - public void init(String args[]) throws MalformedURLException, IOException, Exception { - if (args.length == 0) { - printHelpAndExit(); - } + private static final String ROOT = "/"; - // parse options - parseOptions(args); + public static final String WEB_XML_PATH = "WEB-INF" + File.separator + "web.xml"; - deployedApplicationList = new ArrayList(); + private GrizzlyWebServer ws = null; - } + private String webxmlPath; - private void deployWar(String location, String context) throws Exception { - webxmlPath = appendWarContentToClassPath(location); - - if (context == null) { - context = getContext(webxmlPath); - } - - deploy(webxmlPath, context, webxmlPath + WEB_XML_PATH); + /** + * @param args Command line parameters. + */ + public static void main(String[] args) { + new GrizzlyWebServerDeployer().launch(init(args)); } - private void deployServlet(String location) throws Exception { - deployServlet(location, null); - } - - private void deployServlet(String location, String context) throws Exception { - if (context == null) { - context = getContext("/"); + public static DeployerConfiguration init(String args[]) { + DeployerConfiguration cfg = ConfigurationParser.parseOptions(args, GrizzlyWebServerDeployer.class.getCanonicalName()); + if (logger.isLoggable(Level.INFO)) { + logger.log(Level.INFO, cfg.toString()); } - webxmlPath = appendWarContentToClassPath(null); - deploy(null, context, location); + return cfg; } - 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 { - - // check if it's a expanded folder - // and it doesn't need to contains a web.xml - // a php application could be deployed - File file = new File(dir + File.separator + name); - - if ((file.exists() && file.isDirectory())) { - return true; - } else { - return false; - } - - } - + public void launch(DeployerConfiguration conf) { + try { + ws = new GrizzlyWebServer(conf.port); + URLClassLoader serverLibLoader = createServerLibClassLoader(conf.libraryPath); + configureApplications(conf, serverLibLoader); + configureServer(conf); + // don't start the server is true: useful for unittest + if (!conf.waitToStart) { + ws.start(); } - }); - - // do we have something to deploy - if (files == null || files.length == 0) { - return null; + } catch (Exception e) { + logger.log(Level.SEVERE, "Error while launching deployer.", e); } + } - // 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); + private void configureApplications(DeployerConfiguration conf, URLClassLoader serverLibLoader) throws Exception { + String locations = conf.locations; + if (locations != null) { + if (logger.isLoggable(Level.FINEST)) { + logger.log(Level.FINEST, "Application(s) Found = " + locations); } - + deployApplications(conf, serverLibLoader); } - - 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]); + public void deployApplications(final DeployerConfiguration conf, URLClassLoader serverLibLoader) throws Exception { + if (conf.locations != null && conf.locations.length() > 0) { + final WebApp webDefault = getDefaultSupportWebApp(conf.webdefault); + for (String loc : conf.locations.split(File.pathSeparator)) { + deployApplication(conf, loc, serverLibLoader, webDefault); } } - } - private void deployApplication(String location) throws Exception { - // #1 - if (location.endsWith(".war")) { - deployWar(location, getForcedContext()); - return; - } - - // #2 - if (location.endsWith(".xml")) { + private void deployApplication(final DeployerConfiguration conf, String location, URLClassLoader serverLibLoader, WebApp webDefault) throws Exception { + if (location.endsWith(".war")) {// #1 + deployWar(location, conf.forcedContext, serverLibLoader, webDefault); + } else if (location.endsWith(".xml")) {// #2 // use the forcedContext if set - deployServlet(location, getForcedContext()); - return; - } + deployServlet(location, conf.forcedContext, serverLibLoader, webDefault); + } else { - // #3-#4 - //obtain the list of potential war to deploy - Map fileList = getFile(location); + // #3-#4 + //obtain the list of potential war to deploy + Collection files = getFiles(location, conf.forceWarDeployment); - if (fileList != null) { - for (File file : fileList.values()) { + if (files != null) { + for (File file : files) { - if (file.getName().endsWith(".war")) { - deployWar(file.getPath(), null); - } 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); + if (file.getName().endsWith(".war")) { + deployWar(file.getPath(), null, serverLibLoader, webDefault); } 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. + */ - // #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()); + // #4 : this folder in a expanded war + if (isWebXmlInWebInf(location)) { + deployExpandedWar(String.format("%s%s", location, File.separator), serverLibLoader, webDefault); } else { - // this folder contains multiple war or webapps - File webapp = new File(file.getPath() + File.separator + WEB_XML_PATH); + // #2 : this folder contains a servlet + File webxmlFile2 = new File( + String.format("%s%sweb.xml", location, File.separator)); - if (webapp.exists()) { - deployExpandedWar(file.getPath() + File.separator); + if (webxmlFile2.exists()) { + // this one..see #2 + deployServlet(webxmlFile2.getPath(), serverLibLoader, webDefault); } else { - // not a webapp with web.xml, maybe a php application - deployCustom(file.getPath() + File.separator); - } + // this folder contains multiple war or webapps + File webapp = new File( + String.format( + "%s%s%s", file.getPath(), File.separator, WEB_XML_PATH)); + + if (webapp.exists()) { + deployExpandedWar( + String.format("%s%s", file.getPath(), File.separator), serverLibLoader, webDefault); + } else { + // not a webapp with web.xml, maybe a php application + deployCustom(String.format("%s%s", file.getPath(), File.separator), serverLibLoader, webDefault); + } + } } } } - } } } - /** - * 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) { + private static boolean isWebXmlInWebInf(final String location) { + return new File(String.format("%s%s%s", location, File.separator, WEB_XML_PATH)).exists(); + } - if (path == null || path.trim().length() == 0) { - return DEFAULT_CONTEXT; - } + private void deployWar( + String location, String context, URLClassLoader serverLibLoader, WebApp defaultWebApp) throws Exception { - // need to replace "/" and "\\" par File.separator - // that will fix the case on Windows when user enter c:/... instead of - // c:\\ - - path = path.replaceAll("[/\\\\]+", "\\" + "/"); - path = path.replaceAll("\\\\", "\\" + "/"); - - // remove the trailing File.separator - if (path.endsWith("/") && path.length() > 1) { - path = path.substring(0, path.length() - 1); + final Map.Entry loaderEntry = + explodeAndCraeteWebAppClassLoader(location, serverLibLoader); + webxmlPath = loaderEntry.getKey(); + String ctx = context; + if (ctx == null) { + ctx = getContext(webxmlPath); } - - 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; + deploy(webxmlPath, ctx, webxmlPath + WEB_XML_PATH, loaderEntry.getValue(), defaultWebApp); } - /** - * - * @param path - * @return - */ - public String getServletPath(String path) { + private URLClassLoader createServerLibClassLoader(String libraryPath) throws IOException { + // Must be a better way because that sucks! + String separator = (System.getProperty("os.name").toLowerCase().startsWith("win") ? ROOT : "//"); - if (path == null) { - return DEFAULT_CONTEXT; - } + List urls = new ArrayList(); - // need to replace "\" and "\\" by "/" - path = path.replaceAll("\\\\", "/"); + if (libraryPath != null) { - // the path need to start by "/" - if (!path.startsWith("/")) { - path = DEFAULT_CONTEXT + path; - } + // look if we have multiple folder + String[] libPaths = libraryPath.split(File.pathSeparator); - // we could have multiples options - // /servlet - // /servlet/ - // /servlet/subpath - // /servlet/subpath/ - // /servlet/* or /servlet/*.x - // all theses must return /servlet + if (libPaths != null && libPaths.length > 0) { - // remove the trailing "/" - if (path.endsWith("/") && path.length() > 1) { - path = path.substring(0, path.length() - 1); - } else if (!path.endsWith("/")) { + for (String libPath : libPaths) { + File libFolder = new File(libPath); - // 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 if (index > 0) { - //remove the urlpattern - if (index < path.length()) { - path = path.substring(0, index); + if (libFolder.exists() && libFolder.isDirectory()) { + for (File file : libFolder.listFiles(new ExtensionFileNameFilter(Arrays.asList(".jar")))) { + urls.add(new URL( + String.format( + "jar:file:%s%s!/", separator, + file.getCanonicalPath().replace('\\', '/')))); + } } } } + } + if (logger.isLoggable(Level.FINEST)) { + logger.log(Level.FINEST, String.format("Server library path contains=%s", urls)); } - return path; + return new URLClassLoader(urls.toArray(new URL[urls.size()])); } - /** - * - * @param webApp Contains the info about the web.xml - * @param context context of the application - * @return a list of ServletAdapter with the UrlPattern for each Servlet. - */ - private ConcurrentMap> getServletAdapterList(WebApp webApp, String context) { - - ConcurrentMap> servletAdapterMap = new ConcurrentHashMap>(); - - // validate if we have servletMapping - if (webApp == null || 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; + private void deployServlet(String location, URLClassLoader serverLibLoader, WebApp defaultWebApp) throws Exception { + deployServlet(location, null, serverLibLoader, defaultWebApp); } - /** - * - * @param context - * @return the root folder - */ - private String getRootFolder(String location, String context) { - if (location == null || context == null) { - return location; + private void deployServlet(String location, String context, URLClassLoader serverLibLoader, WebApp defaultWebApp) + throws Exception { + String ctx = context; + if (ctx == null) { + ctx = getContext(ROOT); } - - location = location.replaceAll("[/\\\\]+", "\\" + "/"); - location = location.replaceAll("\\\\", "\\" + "/"); - - int index = location.lastIndexOf(context); - - if (index > -1) { - location = location.substring(0, index); - } - - return location; + final Map.Entry loaderEntry = explodeAndCraeteWebAppClassLoader(null, serverLibLoader); + webxmlPath = loaderEntry.getKey(); + deploy(null, ctx, location, loaderEntry.getValue(), defaultWebApp); } - protected void deployCustom(String location) throws Exception { - webxmlPath = appendWarContentToClassPath(location); - - String context = getContext(webxmlPath); - String root = getRootFolder(location, context); - - deploy(root, context, root + context); + private void deployExpandedWar(String location, URLClassLoader serverLibLoader, WebApp defaultWebApp) throws Exception { + final Map.Entry loaderEntry = explodeAndCraeteWebAppClassLoader(location, serverLibLoader); + webxmlPath = loaderEntry.getKey(); + deploy(webxmlPath, getContext(webxmlPath), webxmlPath + WEB_XML_PATH, loaderEntry.getValue(), defaultWebApp); } - public void deploy(String rootFolder, String context, String path) throws Exception { + private static Collection getFiles(String location, boolean forceWarDeployment) { + Map result = null; + File folder = getFileNotTrailingSlash(location); + if (folder.exists() && folder.isDirectory()) { - if (logger.isLoggable(Level.INFO)) { - logger.log(Level.INFO, "Will deploy application path=" + path); - } + // we only want folders that contains WEB-INF or war files + File files[] = folder.listFiles(new DeployableFilter()); - // deploy default - List webAppList = getDefaultSupportWebApp(); + // do we have something to deploy + if (files != null && files.length != 0) { - if (webAppList == null) { - webAppList = new ArrayList(); - } + // sort list. We want expanded folder first followed by war file. + Arrays.sort(files, new WarFileComparator()); - WebApp webApp = null; - if (path != null && path.toLowerCase().endsWith(".xml")) { - try { - webApp = extractWebxmlInfo(path); - webAppList.add(webApp); - } catch (Exception e) { - logger.log(Level.INFO, "Not a valid WebApp, will be ignored : path=" + path); - } - } + // filter the list. + result = new HashMap(files.length); + for (File file : files) { - - boolean blankContextServletPathFound = false; - boolean defaultContextServletPathFound = false; - - List aliasesUsed = new ArrayList(); - - for (WebApp webApp2 : webAppList) { - // obtain a servletAdapter list - ConcurrentMap> servletAdapterList = getServletAdapterList(webApp2, context); - - - for (ServletAdapter sa : servletAdapterList.keySet()) { - - // set Filters for this context if there are some - setFilters(webApp2, sa); - - // set Listeners - setListeners(webApp2, sa); - - //set root Folder - if (rootFolder != null) { - rootFolder = rootFolder.replaceAll("[/\\\\]+", "\\" + "/"); - rootFolder = rootFolder.replaceAll("\\\\", "\\" + "/"); - sa.setRootFolder(rootFolder); - } - - // create the alias array from the list of urlPattern - String alias[] = getAlias(sa, servletAdapterList.get(sa)); - - if (alias == null) { - alias = new String[]{DEFAULT_CONTEXT}; - } - - // need to be disabled for JSP - sa.setHandleStaticResources(false); - - // enabled it if not / or /* - for (String item : alias) { - if(item.endsWith(DEFAULT_CONTEXT) || item.endsWith("/*")){ - sa.setHandleStaticResources(true); + // add folders + final String filename = file.getName(); + if (file.isDirectory()) { + result.put(filename, file); + } else if (filename.endsWith(".war") && !forceWarDeployment) { + String name = filename.substring(0, filename.length() - ".war".length()); + if (result.containsKey(name)) { + logger.log(Level.INFO, "War file skipped"); + } else { + result.put(name, file); + } + } else if (filename.endsWith(".war") && forceWarDeployment) { + String name = filename.substring(0, filename.length() - ".war".length()); + // we must remove the folder from the list if found + if (result.containsKey(name)) { + result.remove(name); + } + result.put(name, file); + } else { + result.put(filename, file); } } - - - 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()); - } - - // keep trace of deployed application - deployedApplicationList.add(context); - - // keep trace of mapping - aliasesUsed.addAll(Arrays.asList(alias)); - - ws.addGrizzlyAdapter(sa, alias); - - if (DEFAULT_CONTEXT.equals(sa.getServletPath())) { - defaultContextServletPathFound = true; - } - - if ("".equals(sa.getServletPath())) { - blankContextServletPathFound = true; - } - - - } } + return result == null ? null : result.values(); + } - // we need one servlet that will handle "/" - if (!defaultContextServletPathFound) { - logger.log(Level.FINEST, "Adding a ServletAdapter to handle / path"); - - ServletAdapter sa2 = new ServletAdapter(); - - sa2.setContextPath(context); - sa2.setServletPath("/"); - sa2.setHandleStaticResources(true); - sa2.setRootFolder(rootFolder); - - if (logger.isLoggable(Level.FINEST)) { - logger.log(Level.FINEST, "sa context=" + sa2.getContextPath()); - logger.log(Level.FINEST, "sa servletPath=" + sa2.getServletPath()); - - logger.log(Level.FINEST, "sa alias=" + context + DEFAULT_CONTEXT); - logger.log(Level.FINEST, "sa rootFolder=" + sa2.getRootFolder()); - } - - ws.addGrizzlyAdapter(sa2, new String[]{context + DEFAULT_CONTEXT}); - } - - // pour les jsp dans le root du context - if (!blankContextServletPathFound && !aliasesUsed.contains(context + DEFAULT_CONTEXT)) { - logger.log(Level.FINEST, "Adding a ServletAdapter to handle root path"); - - ServletAdapter sa2 = new ServletAdapter(); - - sa2.setContextPath(context); - sa2.setServletPath(""); - sa2.setHandleStaticResources(true); - sa2.setRootFolder(rootFolder); - - if (logger.isLoggable(Level.FINEST)) { - logger.log(Level.FINEST, "sa context=" + sa2.getContextPath()); - logger.log(Level.FINEST, "sa servletPath=" + sa2.getServletPath()); - - logger.log(Level.FINEST, "sa alias=" + context + DEFAULT_CONTEXT); - logger.log(Level.FINEST, "sa rootFolder=" + sa2.getRootFolder()); - } - - ws.addGrizzlyAdapter(sa2, new String[]{context + DEFAULT_CONTEXT}); - - } - - if (logger.isLoggable(Level.INFO)) { - logger.log(Level.INFO, "deployed application path=" + path); - } - - + private static File getFileNotTrailingSlash(String name) { + return new File(removeTrailingPathSeparator(name)); } /** - * - * @param sa ServletAdapter - * @param aliases contains the list of UrlPattern for this ServletAdapter - * @return the alias list for this ServletAdapter + * Return the context that will be used to deploy the application + * + * @param path : file path where the application is + * @return the context */ - public String[] getAlias(ServletAdapter sa, Collection aliases) { + public static String getContext(String path) { + String result; - if (sa == null || aliases == null) { - return null; - } + if (path == null || path.trim().length() == 0) { + result = ROOT; + } else { + result = removeTrailingPathSeparator(fixPath(path)); + int lastIndex = result.lastIndexOf(ROOT); - List aliasList = new ArrayList(); - - for (String urlPattern : aliases) { - - String mapping = ""; - - if (!sa.getServletPath().equals(urlPattern) && urlPattern.indexOf(sa.getServletPath()) > -1) { - mapping = urlPattern.substring(urlPattern.indexOf(sa.getServletPath()) + sa.getServletPath().length()); + if (lastIndex > 0) { + result = ROOT + result.substring(lastIndex + 1); + } else if (lastIndex == -1) { + // need to add the ROOT + result = ROOT + result; } - - // the alias is the context + servletPath + mapping - String aliasTmp = sa.getContextPath() + sa.getServletPath() + mapping; - - if (aliasTmp.indexOf("//") > -1) { - aliasTmp = aliasTmp.replaceAll("//", "/"); - } - - aliasList.add(aliasTmp); - } - - String[] array = new String[aliasList.size()]; - - return aliasList.toArray(array); + return result; } - public void setLocations(String filename) { - locations = filename; + private static String fixPath(String path) { + return path + .replaceAll("[/\\\\]+", '\\' + ROOT) + .replaceAll("\\\\", '\\' + ROOT); } - public String getLocations() { - return locations; - } - - public void setPort(int port) { - this.port = port; - } - - public int getPort() { - return port; - } - - public String getLibraryPath() { - return libraryPath; - } - - public void setLibraryPath(String path) { - this.libraryPath = path; - } - - public String getAutoDeployFolder() { - return autodeployFolder; - } - - public void setAutoDeployFolder(String path) { - this.autodeployFolder = 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(); - System.err.println("Usage: " + GrizzlyWebServerDeployer.class.getCanonicalName()); - System.err.println(); - System.err.println(" --application=[path]* Application(s) path(s)."); - System.err.println(" --port=[port] Runs Servlet on the specified port."); - System.err.println(" --context=[context] Force the context for a servlet."); - System.err.println(" --dontstart=[true/false] Won't start the server."); - System.err.println(" --libraryPath=[path] Add a libraries folder to the classpath."); - System.err.println(" --autodeploy=[path] AutoDeploy to each applications"); - System.err.println(" --cometEnabled Starts the AsyncFilter for Comet"); - System.err.println(" --forceWar Force war's deployment over a expanded folder."); - System.err.println(" --ajpEnabled Enable mod_jk."); - System.err.println(" --help Show this help message."); - System.err.println(" --longhelp Show detailled help message."); - System.err.println(); - System.err.println(" * are mandatory"); - System.exit(1); - } - - public void printLongHelpAndExit() { - System.err.println(); - System.err.println("Usage: " + GrizzlyWebServerDeployer.class.getCanonicalName()); - System.err.println(); - System.err.println(" -a, --application=[path]* Application(s) path(s)."); - System.err.println(); - System.err.println(" Application(s) deployed can be :"); - System.err.println(" Servlet(s), war(s) and expanded war folder(s)."); - System.err.println(" To deploy multiple applications"); - System.err.println(" use File.pathSeparator"); - System.err.println(); - System.err.println(" Example : -a /app.war:/servlet/web.xml:/warfolder/"); - System.err.println(); - System.err.println(" -p, --port=[port] Runs Servlet on the specified port."); - System.err.println(" Default: 8080"); - System.err.println(); - System.err.println(" -c, --context=[context] Force the context for a servlet."); - System.err.println(" Only valid for servlet deployed using"); - System.err.println(" -a [path]/[filename].xml"); - System.err.println(); - System.err.println(" --dontstart=[true/false] Won't start the server."); - System.err.println(" You will need to call the start method."); - System.err.println(" Useful for Unit testing."); - System.err.println(" Default : false"); - System.err.println(); - System.err.println(" --libraryPath=[path] Add a libraries folder to the classpath."); - System.err.println(" You can append multiple folders using"); - System.err.println(" File.pathSeparator"); - System.err.println(); - System.err.println(" Example : --libraryPath=/libs:/common_libs"); - System.err.println(); - System.err.println(" --autodeploy=[path] AutoDeploy to each applications."); - System.err.println(" You could add JSP support."); - System.err.println(" Just add a web.xml that contains Jasper"); - System.err.println(); - System.err.println(" Example : --autodeploy=/autodeploy"); - System.err.println(); - System.err.println(" --cometEnabled=[true/false] Starts the AsyncFilter for Comet."); - System.err.println(" You need to active this for comet applications."); - System.err.println(" Default : false"); - System.err.println(); - System.err.println(" --forceWar=[true/false] Force war's deployment over a expanded folder."); - System.err.println(" Will deploy the war instead of the folder."); - System.err.println(" Default : false"); - System.err.println(); - System.err.println(" --ajpEnabled=[true/false] Enable mod_jk."); - System.err.println(" Default : false"); - System.err.println(); - System.err.println(" Default values will be applied if invalid values are passed."); - System.err.println(); - System.err.println(" * are mandatory"); - 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 ("--longhelp".equals(arg)) { - printLongHelpAndExit(); - } else if ("-a".equals(arg)) { - i++; - if (i < args.length) { - setLocations(args[i]); - } - } else if (arg.startsWith("--application=")) { - setLocations(arg.substring("--application=".length(), arg.length())); - } else if ("-p".equals(arg)) { - i++; - if (i < args.length) { - setPort(Integer.parseInt(args[i])); - } - } else if (arg.startsWith("--port=")) { - String num = arg.substring("--port=".length(), arg.length()); - setPort(Integer.parseInt(num)); - } else if ("-c".equals(arg)) { - i++; - if (i < args.length) { - setForcedContext(args[i]); - } - } else if (arg.startsWith("--context=")) { - setForcedContext(arg.substring("--context=".length(), arg.length())); - } else if (arg.startsWith("--dontstart=")) { - setWaitToStart(Boolean.parseBoolean(arg.substring("--dontstart=".length(), arg.length()))); - } else if (arg.startsWith("--libraryPath=")) { - String value = arg.substring("--libraryPath=".length(), arg.length()); - setLibraryPath(value); - } else if (arg.startsWith("--autodeploy=")) { - String value = arg.substring("--autodeploy=".length(), arg.length()); - setAutoDeployFolder(value); - } else if (arg.startsWith("--cometEnabled=")) { - setCometEnabled(Boolean.parseBoolean(arg.substring("--cometEnabled=".length(), arg.length()))); - } else if (arg.startsWith("--forceWar")) { - setForceWarDeployment(Boolean.parseBoolean(arg.substring("--forceWar=".length(), arg.length()))); - } else if (arg.startsWith("--ajpEnabled")) { - setAjpEnabled(Boolean.parseBoolean(arg.substring("--ajpEnabled=".length(), arg.length()))); - } - - + private static String removeTrailingPathSeparator(String path) { + String result = path; + if (result.endsWith(ROOT) && result.length() > 1) { + result = result.substring(0, result.length() - 1); } - - if (getLocations() == null) { - System.err.println("Illegal War|Jar file or folder location."); - printHelpAndExit(); - } - return true; + return result; } - protected void setServlet(WebApp webApp, ServletAdapter sa, ServletMapping servletMapping) { - // Set the Servlet - List 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; + private static String getRootFolder(String location, String context) { + String result; + if (location == null || context == null) { + result = location; + } else { + result = fixPath(location); + int index = result.lastIndexOf(context); + if (index > -1) { + result = result.substring(0, index); } - } - + return result; } - protected void setListeners(WebApp webApp, ServletAdapter sa) { - if (webApp == null || sa == null) { - return; - } + protected void deployCustom(String location, URLClassLoader serverLibLoader, WebApp defaultSupportWebApp) throws Exception { + final Map.Entry loaderEntry = explodeAndCraeteWebAppClassLoader(location, serverLibLoader); + webxmlPath = loaderEntry.getKey(); - // Add the Listener - List listeners = webApp.getListener(); + String context = getContext(webxmlPath); + String root = getRootFolder(location, context); - if (listeners != null) { - for (Listener element : listeners) { - sa.addServletListener(element.getListenerClass()); - } - } + deploy(root, context, root + context, loaderEntry.getValue(), defaultSupportWebApp); } - protected void setFilters(WebApp webApp, ServletAdapter sa) { + public void deploy( + String rootFolder, String context, String path, URLClassLoader webAppCL, WebApp superApp) throws Exception { - if (webApp == null || sa == null) { - return; + String root = rootFolder; + if (rootFolder != null) { + root = fixPath(rootFolder); } - // 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); - - } - } - - } + if (logger.isLoggable(Level.INFO)) { + logger.log(Level.INFO, "Will deploy application path=" + path); } - - } - - protected Map> getItemMap(List itemList) throws Exception { - // need to find something nicer - Map> itemMap = null; - - if (itemList != null) { - itemMap = new HashMap>(); - // convert it to a Map, will be easier to retrieve values - for (Object object : itemList) { - List list = null; - String key = object.getClass().getSimpleName(); - if (itemMap.containsKey(key)) { - list = itemMap.get(key); - } else { - list = new ArrayList(); - itemMap.put(key, list); - } - list.add(object); + if (path != null) { + WebApp webApp; + if (path.toLowerCase().endsWith(".xml")) { + webApp = extractWebXmlInfo(path); + } else { + webApp = new WebApp(); // empty web app - we might be dealing here with PHP } - } else { - // error handling when list is null ... - throw new Exception("invalid"); + try { + final WebAppAdapter webAppAdapter = + new WebAppAdapter(ws, root, context, webApp, webAppCL, superApp); + ws.addGrizzlyAdapter(webAppAdapter, new String[]{context}); + } catch (Exception e) { + logger.log(Level.INFO, "Not a valid WebApp, will be ignored : path=" + path); + logger.log(Level.INFO, "Error follows.", e); + } } - - return itemMap; } /** @@ -1003,29 +416,29 @@ * ClassLoader. This function as to be executed before the start() because * the new classpath won't take effect. * - * @return the exploded war file location. - * + * TODO This potentially can be replaced by {@link com.sun.grizzly.util.ClassLoaderUtil#createClassloader(java.io.File, ClassLoader)} + * @param appliPath + * @param serverLibLoader + * @return the exploded war file location and web app CL. + * @throws java.io.IOException */ - public String appendWarContentToClassPath(String appliPath) throws MalformedURLException, IOException { + public static Map.Entry explodeAndCraeteWebAppClassLoader( + String appliPath, URLClassLoader serverLibLoader) throws IOException { - String path = null; - File file = null; - URL appRoot = null; - URL classesURL = null; - - if (appliPath != null && appliPath.endsWith(File.pathSeparator)) { - appliPath = appliPath + File.pathSeparator; + appliPath += File.pathSeparator; } - // Must be a better way because that sucks! - String separator = (System.getProperty("os.name").toLowerCase().startsWith("win") ? "/" : "//"); + String separator = (System.getProperty("os.name").toLowerCase().startsWith("win") ? ROOT : "//"); List classpathList = new ArrayList(); + String path = null; + URL appRoot = null; + URL classesURL = null; if (appliPath != null && (appliPath.endsWith(".war") || appliPath.endsWith(".jar"))) { - file = new File(appliPath); + File file = new File(appliPath); appRoot = new URL("jar:file:" + file.getCanonicalPath() + "!/"); classesURL = new URL("jar:file:" + file.getCanonicalPath() + "!/WEB-INF/classes/"); path = ExpandJar.expand(appRoot); @@ -1036,123 +449,55 @@ } if (appliPath != null) { - String absolutePath = new File(path).getAbsolutePath(); - File libFiles = new File(absolutePath + File.separator + "WEB-INF" + File.separator + "lib"); + File libFiles = new File(new File(path).getAbsolutePath() + File.separator + "WEB-INF" + File.separator + "lib"); if (libFiles.exists() && libFiles.isDirectory()) { - for (int i = 0; i < libFiles.listFiles().length; i++) { - classpathList.add(new URL("jar:file:" + separator + libFiles.listFiles()[i].toString().replace('\\', '/') + "!/")); + for (File file : libFiles.listFiles()) { + classpathList.add( + new URL(String.format( + "jar:file:%s%s!/", separator, + file.toString().replace('\\', '/')))); } } } - if (libraryPath != null) { - - // look if we have multiple folder - String[] array = libraryPath.split(File.pathSeparator); - - if (array != null && array.length > 0) { - - for (int i = 0; i < array.length; i++) { - File libFolder = new File(array[i]); - - if (libFolder.exists() && libFolder.isDirectory()) { - for (int k = 0; k < libFolder.listFiles().length; k++) { - classpathList.add(new URL("jar:file:" + separator + libFolder.listFiles()[k].getCanonicalPath().toString().replace('\\', '/') + "!/")); - } - } - } - - } - - } - if (appliPath != null) { classpathList.add(appRoot); classpathList.add(classesURL); } if (logger.isLoggable(Level.FINEST)) { - for (Iterator iterator = classpathList.iterator(); iterator.hasNext();) { - URL url = iterator.next(); - logger.log(Level.FINEST, "Classpath contains=" + url); - } + logger.log(Level.FINEST, String.format("Classpath contains=%s", classpathList)); } - URL urls[] = new URL[classpathList.size()]; - - ClassLoader urlClassloader = new URLClassLoader(classpathList.toArray(urls), Thread.currentThread().getContextClassLoader()); - Thread.currentThread().setContextClassLoader(urlClassloader); - //be sure to that the path ends by File.separator if (path != null && !path.endsWith(File.separator)) { - path = path + File.separator; + path += File.separator; } - return path; + // Linking with serverLibCL + return new AbstractMap.SimpleImmutableEntry( + path, new URLClassLoader(classpathList.toArray(new URL[classpathList.size()]), serverLibLoader)); } - public WebApp extractWebxmlInfo(String webxml) throws Exception { - - if (webxml == null) { - return null; - } - - WebappLoader webappLoader = new WebappLoader(); - WebApp webApp = webappLoader.load(webxml); - - return webApp; + private static WebApp extractWebXmlInfo(String webxml) throws Exception { + return webxml == null ? null : WebappLoader.load(webxml); } - public void launch() { + private void configureServer(DeployerConfiguration conf) { + // comet + if (conf.cometEnabled) { + SelectorThread st = ws.getSelectorThread(); - try { + AsyncHandler asyncHandler = new DefaultAsyncHandler(); + asyncHandler.addAsyncFilter(new CometAsyncFilter()); + st.setAsyncHandler(asyncHandler); - ws = new GrizzlyWebServer(port); + st.setEnableAsyncExecution(true); + } - // need to find which case is it : 1-4. - - /* - * #1 - /temp/hudson.war #2 - /temp/web.xml or any .xml - * web-sample.xml #3 - /temp or /temp/ #4 - /temp/hudson or - * /temp/hudson/ - * - * if #3 find war, it will deployed it, if not, will try #4 if it - * found nothing, try web.xml - */ - - if (locations != null) { - - if (logger.isLoggable(Level.FINEST)) { - logger.log(Level.FINEST, "Application(s) Found = " + locations); - } - - deployApplications(locations); - - } - - // comet - if (cometEnabled) { - SelectorThread st = ws.getSelectorThread(); - - AsyncHandler asyncHandler = new DefaultAsyncHandler(); - asyncHandler.addAsyncFilter(new CometAsyncFilter()); - st.setAsyncHandler(asyncHandler); - - st.setEnableAsyncExecution(true); - } - - if (ajpEnabled) { - ws.enableProtocol(PROTOCOL.AJP); - } - - // don't start the server is true: useful for unittest - if (!waitToStart) { - ws.start(); - } - - } catch (Exception e) { - e.printStackTrace(); + if (conf.ajpEnabled) { + ws.enableProtocol(PROTOCOL.AJP); } } @@ -1172,96 +517,89 @@ } - public void setWaitToStart(boolean dontStart) { - waitToStart = dontStart; - } + /** + * @param webdefault location of webdefault (directory or file). + * @return {@link WebApp} with merged webdefaults if many. + * @throws IllegalArgumentException If provided webdefault doesn't exist or is empty directory. + * @throws Exception If failed to parse web.xml. + */ + private static WebApp getDefaultSupportWebApp(String webdefault) throws Exception { + WebApp result = new WebApp(); + // TODO fields of WebApp are not getting initialized when constructed - public String getForcedContext() { - return forcedContext; - } + if (webdefault != null) { - public void setForcedContext(String forcedContext) { - this.forcedContext = forcedContext; - } + File webdefaultFile = getFileNotTrailingSlash(webdefault); - public List getDefaultSupportWebApp() throws Exception { + if (webdefaultFile.exists()) { + if (webdefaultFile.isDirectory()) { + File xmlFiles[] = webdefaultFile.listFiles(new ExtensionFileNameFilter(Arrays.asList(".xml"))); + if (xmlFiles != null && xmlFiles.length != 0) { + for (File xmlFile : xmlFiles) { + result = extractWebAppAndMerge(result, xmlFile.getPath()); + } - if (autodeployFolder == null) { - return null; - } + } else { + // no .xml files in webdefault directory. + throw new IllegalArgumentException("Webdefault is empty directory."); - // remove ending slash if any - // we need to check if the location is not "/" - if (autodeployFolder.endsWith("/") && autodeployFolder.length() > 1) { - autodeployFolder = autodeployFolder.substring(0, autodeployFolder.length() - 1); - } - - // we try to look of the file's list - - File folder = new File(autodeployFolder); - - if (!folder.exists() || !folder.isDirectory()) { - return null; - } - - // we only want folders or war files - File files[] = folder.listFiles(new FilenameFilter() { - - public boolean accept(File dir, String name) { - - if (name.endsWith(".xml")) { - return true; + } } else { - return false; + // exists && is file + result = extractWebAppAndMerge(result, webdefaultFile.getPath()); + } + } else { + // provided parameter but location is not existent + throw new IllegalArgumentException("Webdefault location is not existent."); } - }); + } + return result; + } - // do we have something to deploy - if (files == null || files.length == 0) { - return null; + private static WebApp extractWebAppAndMerge(WebApp mergeTo, String webxmlLocation) throws Exception { + WebApp webApp = extractWebXmlInfo(webxmlLocation); + if (webApp == null) { + throw new Exception("Invalid webdefault: " + webxmlLocation); } + return mergeTo.mergeWith(webApp); + } - List webappList = new ArrayList(files.length); + private static class DeployableFilter implements FilenameFilter { + public boolean accept(File dir, String name) { + boolean result; + if (name.endsWith(".war")) { + result = true; + } else { - for (File file : files) { - // extract the items from the web.xml - WebApp webApp = extractWebxmlInfo(file.getPath()); + // check if it's a expanded folder + // and it doesn't need to contains a web.xml + // a php application could be deployed + File file = new File(dir + File.separator + name); - if (webApp == null) { - throw new Exception("invalid"); + result = (file.exists() && file.isDirectory()); } - - webappList.add(webApp); + return result; } - - return webappList; - } - /** - * @param args - */ - public static void main(String[] args) { + private static class ExtensionFileNameFilter implements FilenameFilter { + private List extensions; - GrizzlyWebServerDeployer ws = new GrizzlyWebServerDeployer(); + public ExtensionFileNameFilter(List extensions) { + this.extensions = Collections.unmodifiableList(extensions); + } - try { - - /* - * 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) - */ - - // ready to launch - ws.init(args); - ws.launch(); - - } catch (Exception e) { - e.printStackTrace(); + public boolean accept(File dir, String name) { + boolean result = false; + for (String extension : extensions) { + if (name.endsWith(extension)) { + result = true; + break; + } + } + return result; } } } Index: modules/bundles/http-servlet-deployer/src/main/java/com/sun/grizzly/http/servlet/deployer/conf/ConfigurationParser.java =================================================================== --- modules/bundles/http-servlet-deployer/src/main/java/com/sun/grizzly/http/servlet/deployer/conf/ConfigurationParser.java (.../trunk/code) (revision 0) +++ modules/bundles/http-servlet-deployer/src/main/java/com/sun/grizzly/http/servlet/deployer/conf/ConfigurationParser.java (.../branches/deployer-refactoring) (revision 3643) @@ -0,0 +1,208 @@ +/** + * + * 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.conf; + +import java.util.logging.Logger; +import java.util.logging.Level; + +/** + * {@link com.sun.grizzly.http.servlet.deployer.GrizzlyWebServerDeployer} configuration parser. + * + * @author Hubert Iwaniuk + */ +public class ConfigurationParser { + + private static Logger logger = Logger.getLogger(ConfigurationParser.class.getName()); + + /** + * Parse command line parameters. + * + * @param args Command line parameters to parse. + * @param canonicalName Class canonical name. + * + * @return Parsed configuration. + */ + public static DeployerConfiguration parseOptions(String[] args, final String canonicalName) { + DeployerConfiguration conf = new DeployerConfiguration(); + if (args.length == 0) { + printHelpAndExit(canonicalName); + } + + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + + if ("-h".equals(arg) || "--help".equals(arg)) { + printHelpAndExit(canonicalName); + } else if ("--longhelp".equals(arg)) { + printLongHelpAndExit(canonicalName); + } else if ("-a".equals(arg)) { + i++; + if (i < args.length) { + conf.locations = args[i]; + } + } else if (arg.startsWith("--application=")) { + conf.locations = arg.substring("--application=".length(), arg.length()); + } else if ("-p".equals(arg)) { + i++; + if (i < args.length) { + conf.port = Integer.parseInt(args[i]); + } + } else if (arg.startsWith("--port=")) { + String num = arg.substring("--port=".length(), arg.length()); + conf.port = Integer.parseInt(num); + } else if ("-c".equals(arg)) { + i++; + if (i < args.length) { + conf.forcedContext = args[i]; + } + } else if (arg.startsWith("--context=")) { + conf.forcedContext = arg.substring("--context=".length(), arg.length()); + } else if (arg.startsWith("--dontstart=")) { + conf.waitToStart = Boolean + .parseBoolean(arg.substring("--dontstart=".length(), arg.length())); + } else if (arg.startsWith("--libraryPath=")) { + conf.libraryPath = arg.substring("--libraryPath=".length(), arg.length()); + } else if (arg.startsWith("--webdefault=")) { + conf.webdefault = arg.substring("--webdefault=".length(), arg.length()); + } else if (arg.startsWith("--autodeploy=")) { + conf.webdefault = arg.substring("--autodeploy=".length(), arg.length()); + } else if (arg.startsWith("--cometEnabled=")) { + conf.cometEnabled = Boolean + .parseBoolean(arg.substring("--cometEnabled=".length(), arg.length())); + } else if (arg.startsWith("--forceWar")) { + conf.forceWarDeployment = Boolean + .parseBoolean(arg.substring("--forceWar=".length(), arg.length())); + } else if (arg.startsWith("--ajpEnabled")) { + conf.ajpEnabled = Boolean + .parseBoolean(arg.substring("--ajpEnabled=".length(), arg.length())); + } + } + + if (conf.locations == null) { + logger.log(Level.SEVERE, "Illegal War|Jar file or folder location."); + printHelpAndExit(canonicalName); + } + + return conf; + } + + private static void printHelpAndExit(final String canonicalName) { + StringBuilder sb = new StringBuilder(1024); + sb.append("\nUsage: ").append(canonicalName) + .append("\n --application=[path]* Application(s) path(s).\n") + .append(" --port=[port] Runs Servlet on the specified port.\n") + .append(" --context=[context] Force the context for a servlet.\n") + .append(" --dontstart=[true/false] Won't start the server.\n") + .append(" --libraryPath=[path] Add a libraries folder to the classpath.\n") + .append(" --autodeploy=[path] AutoDeploy to each applications\n") + .append(" --webdefault=[path] webdefault to be used by all applications, can be file or dir with multipe web.xmls\n") + .append(" --cometEnabled Starts the AsyncFilter for Comet\n") + .append(" --forceWar Force war's deployment over a expanded folder.\n") + .append(" --ajpEnabled Enable mod_jk.\n") + .append(" --help Show this help message.\n") + .append(" --longhelp Show detailled help message.\n\n") + .append(" * are mandatory"); + logger.log(Level.SEVERE, sb.toString()); + System.exit(1); + } + + private static void printLongHelpAndExit(final String canonicalName) { + System.err.println(); + System.err.println("Usage: " + canonicalName); + System.err.println(); + System.err.println(" -a, --application=[path]* Application(s) path(s)."); + System.err.println(); + System.err.println(" Application(s) deployed can be :"); + System.err.println( + " Servlet(s), war(s) and expanded war folder(s)."); + System.err.println(" To deploy multiple applications"); + System.err.println(" use File.pathSeparator"); + System.err.println(); + System.err.println( + " Example : -a /app.war:/servlet/web.xml:/warfolder/"); + System.err.println(); + System.err.println(" -p, --port=[port] Runs Servlet on the specified port."); + System.err.println(" Default: 8080"); + System.err.println(); + System.err.println(" -c, --context=[context] Force the context for a servlet."); + System.err.println(" Only valid for servlet deployed using"); + System.err.println(" -a [path]/[filename].xml"); + System.err.println(); + System.err.println(" --dontstart=[true/false] Won't start the server."); + System.err.println(" You will need to call the start method."); + System.err.println(" Useful for Unit testing."); + System.err.println(" Default : false"); + System.err.println(); + System.err + .println(" --libraryPath=[path] Add a libraries folder to the classpath."); + System.err.println(" You can append multiple folders using"); + System.err.println(" File.pathSeparator"); + System.err.println(); + System.err + .println(" Example : --libraryPath=/libs:/common_libs"); + System.err.println(); + System.err.println(" --autodeploy=[path] AutoDeploy to each applications."); + System.err.println(" You could add JSP support."); + System.err.println(" Just add a web.xml that contains Jasper"); + System.err.println(); + System.err.println(" Example : --autodeploy=/autodeploy"); + System.err.println(); + System.err.println(" --webdefault=[path] webdefault to be used by all applications, can be file or dir with multipe web.xmls."); + System.err.println(" If you want to add only one webdefault point it to web.xml file,"); + System.err.println(" If you want multiple files to be included put them in one dir and provide this location here."); + System.err.println(); + System.err.println(" Example : --webdefault=webdefault.xml"); + System.err.println(); + System.err.println(" --cometEnabled=[true/false] Starts the AsyncFilter for Comet."); + System.err.println( + " You need to active this for comet applications."); + System.err.println(" Default : false"); + System.err.println(); + System.err.println( + " --forceWar=[true/false] Force war's deployment over a expanded folder."); + System.err + .println(" Will deploy the war instead of the folder."); + System.err.println(" Default : false"); + System.err.println(); + System.err.println(" --ajpEnabled=[true/false] Enable mod_jk."); + System.err.println(" Default : false"); + System.err.println(); + System.err.println(" Default values will be applied if invalid values are passed."); + System.err.println(); + System.err.println(" * are mandatory"); + System.exit(1); + } +} Index: modules/bundles/http-servlet-deployer/src/main/java/com/sun/grizzly/http/servlet/deployer/conf/DeployerConfiguration.java =================================================================== --- modules/bundles/http-servlet-deployer/src/main/java/com/sun/grizzly/http/servlet/deployer/conf/DeployerConfiguration.java (.../trunk/code) (revision 0) +++ modules/bundles/http-servlet-deployer/src/main/java/com/sun/grizzly/http/servlet/deployer/conf/DeployerConfiguration.java (.../branches/deployer-refactoring) (revision 3643) @@ -0,0 +1,68 @@ +/** + * + * 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.conf; + +/** + * Configuration of {@link com.sun.grizzly.http.servlet.deployer.GrizzlyWebServerDeployer}. + * + * @author Hubert Iwaniuk + */ +public class DeployerConfiguration { + public String locations; + public int port = 8080; + public String forcedContext; + public boolean waitToStart = false; + public String libraryPath; + public String webdefault; + public boolean cometEnabled = false; + public boolean forceWarDeployment = false; + public boolean ajpEnabled = false; + + @Override + public String toString() { + return "DeployerConfiguration{" + + "locations='" + locations + '\'' + + ", port=" + port + + ", forcedContext='" + forcedContext + '\'' + + ", waitToStart=" + waitToStart + + ", libraryPath='" + libraryPath + '\'' + + ", webdefault='" + webdefault + '\'' + + ", cometEnabled=" + cometEnabled + + ", forceWarDeployment=" + forceWarDeployment + + ", ajpEnabled=" + ajpEnabled + + '}'; + } +}