Jetty 12.0.x deployment (#8208)

Deploy webapps for different environments from the same webapps directory.
The maximal environment known to the AppProviders is used as the default environment.
An explicit environment can be set in a properties file for an application, which is also used for property substitution in any context xml file.
This commit is contained in:
Greg Wilkins 2022-06-30 09:51:19 +10:00 committed by GitHub
parent 5304233b15
commit ea5bedf072
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
80 changed files with 879 additions and 822 deletions

View File

@ -90,6 +90,11 @@
<artifactId>jetty-deploy</artifactId> <artifactId>jetty-deploy</artifactId>
<version>12.0.0-SNAPSHOT</version> <version>12.0.0-SNAPSHOT</version>
</dependency> </dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-ee</artifactId>
<version>12.0.0-SNAPSHOT</version>
</dependency>
<dependency> <dependency>
<groupId>org.eclipse.jetty.fcgi</groupId> <groupId>org.eclipse.jetty.fcgi</groupId>
<artifactId>fcgi-client</artifactId> <artifactId>fcgi-client</artifactId>

View File

@ -56,5 +56,9 @@
<artifactId>jetty-test-helper</artifactId> <artifactId>jetty-test-helper</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-ee</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -15,11 +15,6 @@
<Set name="contexts"> <Set name="contexts">
<Ref refid="Contexts" /> <Ref refid="Contexts" />
</Set> </Set>
<!-- TODO move this to an environment -->
<Call name="setContextAttribute">
<Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
<Arg>.*/jetty-jakarta-servlet-api-[^/]*\.jar$|.*/.*jakarta.servlet.jsp.jstl-.*\.jar$</Arg>
</Call>
<!-- Add a customize step to the deployment lifecycle --> <!-- Add a customize step to the deployment lifecycle -->
<!-- uncomment and replace DebugBinding with your extended AppLifeCycle.Binding class <!-- uncomment and replace DebugBinding with your extended AppLifeCycle.Binding class

View File

@ -10,18 +10,3 @@ lib/jetty-deploy-${jetty.version}.jar
[xml] [xml]
etc/jetty-deploy.xml etc/jetty-deploy.xml
[ini-template]
# Monitored directory name (relative to $jetty.base)
# jetty.deploy.monitoredDir=webapps
# - OR -
# Monitored directory path (fully qualified)
# jetty.deploy.monitoredPath=/var/www/webapps
# Defaults Descriptor for all deployed webapps
# jetty.deploy.defaultsDescriptorPath=${jetty.base}/etc/webdefault.xml
# Monitored directory scan period (seconds)
# jetty.deploy.scanInterval=1
# Whether to extract *.war files
# jetty.deploy.extractWars=true

View File

@ -14,6 +14,7 @@
module org.eclipse.jetty.deploy module org.eclipse.jetty.deploy
{ {
requires java.xml; requires java.xml;
requires org.eclipse.jetty.ee;
requires org.eclipse.jetty.xml; requires org.eclipse.jetty.xml;
requires org.eclipse.jetty.server; requires org.eclipse.jetty.server;
requires org.slf4j; requires org.slf4j;

View File

@ -13,36 +13,59 @@
package org.eclipse.jetty.deploy; package org.eclipse.jetty.deploy;
import java.io.File;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.eclipse.jetty.deploy.util.FileID;
import org.eclipse.jetty.ee.Deployable;
import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.Attributes;
/** /**
* The information about an App that is managed by the {@link DeploymentManager} * The information about an App that is managed by the {@link DeploymentManager}.
*/ */
public class App public class App
{ {
private final DeploymentManager _manager; private final DeploymentManager _manager;
private final AppProvider _provider; private final AppProvider _provider;
private final String _environment;
private final String _filename; private final String _filename;
private final Map<String, String> _properties = new HashMap<>();
private ContextHandler _context; private ContextHandler _context;
/** /**
* Create an App with specified Origin ID and archivePath * Create an App with specified Origin ID and archivePath
* * <p>
* Any properties file that exists with the same {@link FileID#getDot3Basename(String)} as the
* filename passed will be used to initialize the properties returned by {@link #getProperties()}.
* @param manager the deployment manager * @param manager the deployment manager
* @param provider the app provider * @param provider the app provider
* @param environment the name of the environment or null for the server environment.
* @param filename the filename of the base resource of the application * @param filename the filename of the base resource of the application
* @see App#getFilename() * @see App#getFilename()
* @see App#getContextPath() * @see App#getContextPath()
*/ */
public App(DeploymentManager manager, AppProvider provider, String environment, String filename) public App(DeploymentManager manager, AppProvider provider, String filename)
{ {
_manager = manager; _manager = manager;
_provider = provider; _provider = provider;
_environment = environment;
_filename = filename; _filename = filename;
try
{
String basename = FileID.getDot3Basename(filename);
File properties = new File(basename + ".properties");
if (properties.exists())
{
Properties p = new Properties();
p.load(new FileInputStream(properties));
p.keySet().stream().map(Object::toString).forEach(k -> _properties.put(k, p.getProperty(k)));
}
}
catch (Exception e)
{
throw new RuntimeException(e);
}
} }
/** /**
@ -61,6 +84,11 @@ public class App
return _provider; return _provider;
} }
public Map<String, String> getProperties()
{
return _properties;
}
/** /**
* Get ContextHandler for the App. * Get ContextHandler for the App.
* *
@ -74,19 +102,7 @@ public class App
public ContextHandler getContextHandler() throws Exception public ContextHandler getContextHandler() throws Exception
{ {
if (_context == null) if (_context == null)
{
_context = getAppProvider().createContextHandler(this); _context = getAppProvider().createContextHandler(this);
Attributes.Mapped attributes = _manager.getContextAttributes();
if (attributes != null && attributes.size() > 0)
{
// Merge the manager attributes under the existing attributes
for (String name : attributes.getAttributeNameSet())
{
_context.setAttribute(name, attributes.getAttribute(name));
}
}
}
return _context; return _context;
} }
@ -117,9 +133,16 @@ public class App
return _context == null ? null : _context.getContextPath(); return _context == null ? null : _context.getContextPath();
} }
public String getEnvironment() /**
* Get the environment name.
* If the property "environment" exists, then that is returned as the environment, otherwise
* the {@link DeploymentManager#getDefaultEnvironmentName()} is returned.
* @return The {@link org.eclipse.jetty.util.component.Environment} name for the application.
*/
public String getEnvironmentName()
{ {
return _environment; String name = getProperties().get(Deployable.ENVIRONMENT);
return name == null ? _manager.getDefaultEnvironmentName() : name;
} }
/** /**
@ -135,6 +158,6 @@ public class App
@Override @Override
public String toString() public String toString()
{ {
return "App[" + _context + "," + _filename + "]"; return "App@%x[%s,%s,%s]".formatted(hashCode(), getEnvironmentName(), _context, _filename);
} }
} }

View File

@ -40,4 +40,10 @@ public interface AppProvider extends LifeCycle
* @throws Exception if unable to create context * @throws Exception if unable to create context
*/ */
ContextHandler createContextHandler(App app) throws Exception; ContextHandler createContextHandler(App app) throws Exception;
/**
*
* @return The name of the {@link org.eclipse.jetty.util.component.Environment} this provider is for.
*/
String getEnvironmentName();
} }

View File

@ -13,7 +13,6 @@
package org.eclipse.jetty.deploy; package org.eclipse.jetty.deploy;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -32,18 +31,17 @@ import org.eclipse.jetty.deploy.bindings.StandardUndeployer;
import org.eclipse.jetty.deploy.graph.Edge; import org.eclipse.jetty.deploy.graph.Edge;
import org.eclipse.jetty.deploy.graph.Node; import org.eclipse.jetty.deploy.graph.Node;
import org.eclipse.jetty.deploy.graph.Path; import org.eclipse.jetty.deploy.graph.Path;
import org.eclipse.jetty.ee.Deployable;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.util.Attributes;
import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.ManagedOperation; import org.eclipse.jetty.util.annotation.ManagedOperation;
import org.eclipse.jetty.util.annotation.Name; import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.component.Environment;
import org.eclipse.jetty.util.thread.AutoLock; import org.eclipse.jetty.util.thread.AutoLock;
import org.eclipse.jetty.xml.XmlConfiguration;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -125,11 +123,26 @@ public class DeploymentManager extends ContainerLifeCycle
private final List<AppProvider> _providers = new ArrayList<AppProvider>(); private final List<AppProvider> _providers = new ArrayList<AppProvider>();
private final AppLifeCycle _lifecycle = new AppLifeCycle(); private final AppLifeCycle _lifecycle = new AppLifeCycle();
private final Queue<AppEntry> _apps = new ConcurrentLinkedQueue<AppEntry>(); private final Queue<AppEntry> _apps = new ConcurrentLinkedQueue<AppEntry>();
private Attributes.Mapped _contextAttributes = new Attributes.Mapped();
private ContextHandlerCollection _contexts; private ContextHandlerCollection _contexts;
private boolean _useStandardBindings = true; private boolean _useStandardBindings = true;
private String _defaultLifeCycleGoal = AppLifeCycle.STARTED; private String _defaultLifeCycleGoal = AppLifeCycle.STARTED;
/**
* Get the default {@link Environment} name for deployed applications.
* @return The name of environment known to the {@link AppProvider}s returned from
* {@link #getAppProviders()} that matches {@link Deployable#EE_ENVIRONMENT_NAME}.
* If multiple names match, then the maximal name, according to {@link Deployable#EE_ENVIRONMENT_COMPARATOR}
* is returned.
*/
public String getDefaultEnvironmentName()
{
return _providers.stream()
.map(AppProvider::getEnvironmentName)
.filter(Deployable.EE_ENVIRONMENT_NAME)
.max(Deployable.EE_ENVIRONMENT_COMPARATOR)
.orElse(null);
}
/** /**
* Receive an app for processing. * Receive an app for processing.
* *
@ -139,7 +152,7 @@ public class DeploymentManager extends ContainerLifeCycle
*/ */
public void addApp(App app) public void addApp(App app)
{ {
LOG.debug("Deployable added: {}", app.getFilename()); LOG.info("addApp: {}", app);
AppEntry entry = new AppEntry(); AppEntry entry = new AppEntry();
entry.app = app; entry.app = app;
entry.setLifeCycleNode(_lifecycle.getNodeByName("undeployed")); entry.setLifeCycleNode(_lifecycle.getNodeByName("undeployed"));
@ -373,22 +386,6 @@ public class DeploymentManager extends ContainerLifeCycle
return ret; return ret;
} }
/**
* Get a contextAttribute that will be set for every Context deployed by this provider.
*
* @param name context attribute name
* @return the context attribute value
*/
public Object getContextAttribute(String name)
{
return _contextAttributes.getAttribute(name);
}
public Attributes.Mapped getContextAttributes()
{
return _contextAttributes;
}
@ManagedAttribute("Deployed Contexts") @ManagedAttribute("Deployed Contexts")
public ContextHandlerCollection getContexts() public ContextHandlerCollection getContexts()
{ {
@ -421,6 +418,7 @@ public class DeploymentManager extends ContainerLifeCycle
*/ */
public void removeApp(App app) public void removeApp(App app)
{ {
LOG.info("removeApp: {}", app);
Iterator<AppEntry> it = _apps.iterator(); Iterator<AppEntry> it = _apps.iterator();
while (it.hasNext()) while (it.hasNext())
{ {
@ -430,7 +428,6 @@ public class DeploymentManager extends ContainerLifeCycle
if (!AppLifeCycle.UNDEPLOYED.equals(entry.lifecyleNode.getName())) if (!AppLifeCycle.UNDEPLOYED.equals(entry.lifecyleNode.getName()))
requestAppGoal(entry.app, AppLifeCycle.UNDEPLOYED); requestAppGoal(entry.app, AppLifeCycle.UNDEPLOYED);
it.remove(); it.remove();
LOG.debug("Deployable removed: {}", entry.app);
} }
} }
} }
@ -450,16 +447,6 @@ public class DeploymentManager extends ContainerLifeCycle
} }
} }
/**
* Remove a contextAttribute that will be set for every Context deployed by this provider.
*
* @param name the context attribute name
*/
public void removeContextAttribute(String name)
{
_contextAttributes.removeAttribute(name);
}
/** /**
* Move an {@link App} through the {@link AppLifeCycle} to the desired {@link Node}, executing each lifecycle step * Move an {@link App} through the {@link AppLifeCycle} to the desired {@link Node}, executing each lifecycle step
* in the process to reach the desired state. * in the process to reach the desired state.
@ -571,23 +558,6 @@ public class DeploymentManager extends ContainerLifeCycle
requestAppGoal(appentry, nodeName); requestAppGoal(appentry, nodeName);
} }
/**
* Set a contextAttribute that will be set for every Context deployed by this provider.
*
* @param name the context attribute name
* @param value the context attribute value
*/
public void setContextAttribute(String name, Object value)
{
_contextAttributes.setAttribute(name, value);
}
public void setContextAttributes(Attributes contextAttributes)
{
this._contextAttributes.clearAttributes();
this._contextAttributes.addAll(contextAttributes);
}
public void setContexts(ContextHandlerCollection contexts) public void setContexts(ContextHandlerCollection contexts)
{ {
this._contexts = contexts; this._contexts = contexts;
@ -634,10 +604,4 @@ public class DeploymentManager extends ContainerLifeCycle
{ {
return _lifecycle.getNodes(); return _lifecycle.getNodes();
} }
public void scope(XmlConfiguration xmlc, Resource webapp)
throws IOException
{
xmlc.setJettyStandardIdsAndProperties(getServer(), webapp);
}
} }

View File

@ -1,114 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.deploy;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.ManagedOperation;
import org.eclipse.jetty.util.annotation.Name;
import org.eclipse.jetty.util.component.Dumpable;
import org.eclipse.jetty.util.resource.Resource;
/**
* FileConfigurationManager
*
* Supplies properties defined in a file.
*/
@ManagedObject("Configure deployed webapps via properties")
public class PropertiesConfigurationManager implements ConfigurationManager, Dumpable
{
private String _properties;
private final Map<String, String> _map = new HashMap<>();
public PropertiesConfigurationManager(String properties)
{
if (properties != null)
{
try
{
setFile(properties);
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
}
public PropertiesConfigurationManager()
{
this(null);
}
public void setFile(String resource) throws IOException
{
_properties = resource;
_map.clear();
loadProperties(_properties);
}
@ManagedAttribute("A file or URL of properties")
public String getFile()
{
return _properties;
}
@ManagedOperation("Set a property")
public void put(@Name("name") String name, @Name("value") String value)
{
_map.put(name, value);
}
@Override
public Map<String, String> getProperties()
{
return _map;
}
private void loadProperties(String resource) throws FileNotFoundException, IOException
{
Resource file = Resource.newResource(resource);
if (file != null && file.exists())
{
Properties properties = new Properties();
properties.load(file.getInputStream());
for (Map.Entry<Object, Object> entry : properties.entrySet())
_map.put(entry.getKey().toString(), String.valueOf(entry.getValue()));
}
}
@Override
public String toString()
{
return String.format("%s@%x{%s}", this.getClass(), hashCode(), _properties);
}
@Override
public String dump()
{
return Dumpable.dump(this);
}
@Override
public void dump(Appendable out, String indent) throws IOException
{
Dumpable.dumpObjects(out, indent, toString(), _map);
}
}

View File

@ -15,27 +15,23 @@ package org.eclipse.jetty.deploy.providers;
import java.io.File; import java.io.File;
import java.io.FilenameFilter; import java.io.FilenameFilter;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.eclipse.jetty.deploy.App; import org.eclipse.jetty.deploy.App;
import org.eclipse.jetty.deploy.ConfigurationManager;
import org.eclipse.jetty.deploy.util.FileID; import org.eclipse.jetty.deploy.util.FileID;
import org.eclipse.jetty.ee.Deployable;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.Loader;
import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.Environment; import org.eclipse.jetty.util.component.Environment;
import org.eclipse.jetty.util.resource.JarResource;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.xml.XmlConfiguration; import org.eclipse.jetty.xml.XmlConfiguration;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -55,6 +51,7 @@ import org.slf4j.LoggerFactory;
* implements some heuristics to ignore some files found in the scans: <ul> * implements some heuristics to ignore some files found in the scans: <ul>
* <li>Hidden files (starting with ".") are ignored</li> * <li>Hidden files (starting with ".") are ignored</li>
* <li>Directories with names ending in ".d" are ignored</li> * <li>Directories with names ending in ".d" are ignored</li>
* <li>Property files with names ending in ".properties" are not deployed.</li>
* <li>If a directory and a WAR file exist ( eg foo/ and foo.war) then the directory is assumed to be * <li>If a directory and a WAR file exist ( eg foo/ and foo.war) then the directory is assumed to be
* the unpacked WAR and only the WAR is deployed (which may reused the unpacked directory)</li> * the unpacked WAR and only the WAR is deployed (which may reused the unpacked directory)</li>
* <li>If a directory and a matching XML file exist ( eg foo/ and foo.xml) then the directory is assumed to be * <li>If a directory and a matching XML file exist ( eg foo/ and foo.xml) then the directory is assumed to be
@ -62,20 +59,23 @@ import org.slf4j.LoggerFactory;
* <li>If a WAR file and a matching XML exist (eg foo.war and foo.xml) then the WAR is assumed to * <li>If a WAR file and a matching XML exist (eg foo.war and foo.xml) then the WAR is assumed to
* be configured by the XML and only the XML is deployed. * be configured by the XML and only the XML is deployed.
* </ul> * </ul>
* <p>
* Only {@link App}s discovered that report {@link App#getEnvironmentName()} matching this providers
* {@link #getEnvironmentName()} will be deployed.
* </p>
* <p>For XML configured contexts, the ID map will contain a reference to the {@link Server} instance called "Server" and * <p>For XML configured contexts, the ID map will contain a reference to the {@link Server} instance called "Server" and
* properties for the webapp file as "jetty.webapp" and directory as "jetty.webapps". * properties for the webapp file such as "jetty.webapp" and directory as "jetty.webapps".
* The properties will be initialized with:<ul>
* <li>The properties set on the application via {@link App#getProperties()}; otherwise:</li>
* <li>The properties set on this provider via {@link #getProperties()}</li>
* </ul>
*/ */
@ManagedObject("Provider for start-up deployement of webapps based on presence in directory") @ManagedObject("Provider for start-up deployment of webapps based on presence in directory")
public class ContextProvider extends ScanningAppProvider public class ContextProvider extends ScanningAppProvider
{ {
private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(ContextProvider.class); private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(ContextProvider.class);
private boolean _extract = false; private final Map<String, String> _properties = new HashMap<>();
private boolean _parentLoaderPriority = false;
private ConfigurationManager _configurationManager;
private String _defaultsDescriptor;
private File _tempDirectory;
private String[] _configurationClasses;
public class Filter implements FilenameFilter public class Filter implements FilenameFilter
{ {
@ -87,32 +87,37 @@ public class ContextProvider extends ScanningAppProvider
String lowerName = name.toLowerCase(Locale.ENGLISH); String lowerName = name.toLowerCase(Locale.ENGLISH);
// TODO close resource! try (Resource resource = Resource.newResource(new File(dir, name)))
Resource resource = Resource.newResource(new File(dir, name));
if (getMonitoredResources().stream().anyMatch(resource::isSame))
return false;
// ignore hidden files
if (lowerName.startsWith("."))
return false;
// Ignore some directories
if (resource.isDirectory())
{ {
// is it a nominated config directory if (getMonitoredResources().stream().anyMatch(resource::isSame))
if (lowerName.endsWith(".d"))
return false; return false;
// is it an unpacked directory for an existing war file? // ignore hidden files
if (exists(name + ".war") || exists(name + ".WAR")) if (lowerName.startsWith("."))
return false; return false;
// is it a directory for an existing xml file? // ignore property files
if (exists(name + ".xml") || exists(name + ".XML")) if (lowerName.endsWith(".properties"))
return false; return false;
//is it a sccs dir? // Ignore some directories
return !"cvs".equals(lowerName) && !"cvsroot".equals(lowerName); // OK to deploy it then if (resource.isDirectory())
{
// is it a nominated config directory
if (lowerName.endsWith(".d"))
return false;
// is it an unpacked directory for an existing war file?
if (exists(name + ".war") || exists(name + ".WAR"))
return false;
// is it a directory for an existing xml file?
if (exists(name + ".xml") || exists(name + ".XML"))
return false;
//is it a sccs dir?
return !"cvs".equals(lowerName) && !"cvsroot".equals(lowerName); // OK to deploy it then
}
} }
// else is it a war file // else is it a war file
@ -131,161 +136,186 @@ public class ContextProvider extends ScanningAppProvider
setScanInterval(0); setScanInterval(0);
} }
/** public Map<String, String> getProperties()
* Get the extractWars.
*
* @return the extractWars
* @deprecated use {@link #isExtract()}
*/
@Deprecated
public boolean isExtractWars()
{ {
return isExtract(); return _properties;
} }
/** /**
* @return True if WAR and JAR are extraced on deploy. * Get the extractWars.
* This is equivalent to getting the {@link Deployable#EXTRACT_WARS} property.
*
* @return the extractWars
*/ */
@ManagedAttribute("extract WAR and JAR files") @ManagedAttribute("extract war files")
public boolean isExtract() public boolean isExtractWars()
{ {
return _extract; return Boolean.parseBoolean(_properties.get(Deployable.EXTRACT_WARS));
} }
/** /**
* Set the extractWars. * Set the extractWars.
* This is equivalent to setting the {@link Deployable#EXTRACT_WARS} property.
* *
* @param extract the extractWars to set * @param extractWars the extractWars to set
* @deprecated use {@link #setExtract(boolean)}
*/ */
@Deprecated public void setExtractWars(boolean extractWars)
public void setExtractWars(boolean extract)
{ {
setExtract(extract); _properties.put(Deployable.EXTRACT_WARS, Boolean.toString(extractWars));
}
/**
* Set to extract WAR and JAR files.
*
* @param extract the extractWars to set
*/
public void setExtract(boolean extract)
{
_extract = extract;
} }
/** /**
* Get the parentLoaderPriority. * Get the parentLoaderPriority.
* This is equivalent to getting the {@link Deployable#PARENT_LOADER_PRIORITY} property.
* *
* @return the parentLoaderPriority * @return the parentLoaderPriority
*/ */
@ManagedAttribute("parent classloader has priority") @ManagedAttribute("parent classloader has priority")
public boolean isParentLoaderPriority() public boolean isParentLoaderPriority()
{ {
return _parentLoaderPriority; return Boolean.parseBoolean(_properties.get(Deployable.PARENT_LOADER_PRIORITY));
} }
/** /**
* Set the parentLoaderPriority. * Set the parentLoaderPriority.
* This is equivalent to setting the {@link Deployable#PARENT_LOADER_PRIORITY} property.
* *
* @param parentLoaderPriority the parentLoaderPriority to set * @param parentLoaderPriority the parentLoaderPriority to set
*/ */
public void setParentLoaderPriority(boolean parentLoaderPriority) public void setParentLoaderPriority(boolean parentLoaderPriority)
{ {
_parentLoaderPriority = parentLoaderPriority; _properties.put(Deployable.PARENT_LOADER_PRIORITY, Boolean.toString(parentLoaderPriority));
} }
/** /**
* Get the defaultsDescriptor. * Get the defaultsDescriptor.
* This is equivalent to getting the {@link Deployable#DEFAULTS_DESCRIPTOR} property.
* *
* @return the defaultsDescriptor * @return the defaultsDescriptor
*/ */
@ManagedAttribute("default descriptor for webapps") @ManagedAttribute("default descriptor for webapps")
public String getDefaultsDescriptor() public String getDefaultsDescriptor()
{ {
return _defaultsDescriptor; return _properties.get(Deployable.DEFAULTS_DESCRIPTOR);
} }
/** /**
* Set the defaultsDescriptor. * Set the defaultsDescriptor.
* This is equivalent to setting the {@link Deployable#DEFAULTS_DESCRIPTOR} property.
* *
* @param defaultsDescriptor the defaultsDescriptor to set * @param defaultsDescriptor the defaultsDescriptor to set
*/ */
public void setDefaultsDescriptor(String defaultsDescriptor) public void setDefaultsDescriptor(String defaultsDescriptor)
{ {
_defaultsDescriptor = defaultsDescriptor; _properties.put(Deployable.DEFAULTS_DESCRIPTOR, defaultsDescriptor);
}
public ConfigurationManager getConfigurationManager()
{
return _configurationManager;
} }
/** /**
* Set the configurationManager. * This is equivalent to setting the {@link Deployable#CONFIGURATION_CLASSES} property.
* * @param configurations The configuration class names as a comma separated list
* @param configurationManager the configurationManager to set
*/ */
public void setConfigurationManager(ConfigurationManager configurationManager) public void setConfigurationClasses(String configurations)
{ {
updateBean(_configurationManager, configurationManager); setConfigurationClasses(StringUtil.isBlank(configurations) ? null : configurations.split(","));
_configurationManager = configurationManager;
} }
/** /**
* This is equivalent to setting the {@link Deployable#CONFIGURATION_CLASSES} property.
* @param configurations The configuration class names. * @param configurations The configuration class names.
*/ */
public void setConfigurationClasses(String[] configurations) public void setConfigurationClasses(String[] configurations)
{ {
_configurationClasses = configurations == null ? null : configurations.clone(); _properties.put(Deployable.CONFIGURATION_CLASSES, (configurations == null)
} ? null
: String.join(",", configurations));
@ManagedAttribute("configuration classes for webapps to be processed through")
public String[] getConfigurationClasses()
{
return _configurationClasses;
} }
/** /**
* Set the Work directory where unpacked WAR files are managed from. *
* This is equivalent to getting the {@link Deployable#CONFIGURATION_CLASSES} property.
* @return The configuration class names.
*/
@ManagedAttribute("configuration classes for webapps to be processed through")
public String[] getConfigurationClasses()
{
String cc = _properties.get(Deployable.CONFIGURATION_CLASSES);
return cc == null ? new String[0] : cc.split(",");
}
/**
* Set the temporary directory for deployment.
* <p> * <p>
* Default is the same as the <code>java.io.tmpdir</code> System Property. * This is equivalent to setting the {@link Deployable#BASE_TEMP_DIR} property.
* If not set, then the <code>java.io.tmpdir</code> System Property is used.
*
* @param directory the new work directory
*/
public void setTempDir(String directory)
{
_properties.put(Deployable.BASE_TEMP_DIR, directory);
}
/**
* Set the temporary directory for deployment.
* <p>
* This is equivalent to setting the {@link Deployable#BASE_TEMP_DIR} property.
* If not set, then the <code>java.io.tmpdir</code> System Property is used.
* *
* @param directory the new work directory * @param directory the new work directory
*/ */
public void setTempDir(File directory) public void setTempDir(File directory)
{ {
_tempDirectory = directory; _properties.put(Deployable.BASE_TEMP_DIR, directory.getAbsolutePath());
} }
/** /**
* Get the user supplied Work Directory. * Get the temporary directory for deployment.
* <p>
* This is equivalent to getting the {@link Deployable#BASE_TEMP_DIR} property.
* *
* @return the user supplied work directory (null if user has not set Temp Directory yet) * @return the user supplied work directory (null if user has not set Temp Directory yet)
*/ */
@ManagedAttribute("temp directory for use, null if no user set temp directory") @ManagedAttribute("temp directory for use, null if no user set temp directory")
public File getTempDir() public File getTempDir()
{ {
return _tempDirectory; String tmpDir = _properties.get(Deployable.BASE_TEMP_DIR);
return tmpDir == null ? null : new File(tmpDir);
} }
protected void initializeWebAppContextDefaults(ContextHandler webapp) protected ContextHandler initializeContextHandler(Object context, File file, Map<String, String> properties)
{ {
if (_defaultsDescriptor != null) // find the ContextHandler
webapp.setAttribute("defaultsDescriptor", _defaultsDescriptor); ContextHandler contextHandler;
if (context instanceof ContextHandler handler)
if (_tempDirectory != null) contextHandler = handler;
else if (Supplier.class.isAssignableFrom(context.getClass()))
{ {
// TODO work out temp directory @SuppressWarnings("unchecked")
// TODO set if the temp directory is persistent Supplier<ContextHandler> provider = (Supplier<ContextHandler>)context;
webapp.setAttribute(Server.BASE_TEMP_DIR_ATTR, _tempDirectory); contextHandler = provider.get();
} }
else
{
throw new IllegalStateException("No ContextHandler for " + context);
}
assert contextHandler != null;
initializeContextPath(contextHandler, file.getName());
if (file.isDirectory())
contextHandler.setBaseResource(Resource.newResource(file));
if (context instanceof Deployable deployable)
deployable.initializeDefaults(properties);
return contextHandler;
} }
@Override @Override
public ContextHandler createContextHandler(final App app) throws Exception public ContextHandler createContextHandler(final App app) throws Exception
{ {
Environment environment = Environment.get(app.getEnvironment()); Environment environment = Environment.get(app.getEnvironmentName());
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("createContextHandler {} in {}", app, environment); LOG.debug("createContextHandler {} in {}", app, environment);
@ -295,52 +325,31 @@ public class ContextProvider extends ScanningAppProvider
{ {
Thread.currentThread().setContextClassLoader(environment.getClassLoader()); Thread.currentThread().setContextClassLoader(environment.getClassLoader());
Resource resource = Resource.newResource(app.getFilename()); // Create de-aliased file
if (!resource.exists()) File file = new File(app.getFilename()).toPath().toRealPath().toFile().getCanonicalFile().getAbsoluteFile();
throw new IllegalStateException("App resource does not exist " + resource); if (!file.exists())
resource = unpack(resource); // TODO move unpacking to below. throw new IllegalStateException("App resource does not exist " + file);
File file = resource.getFile(); // prepare properties
Map<String, String> properties = new HashMap<>();
properties.putAll(getProperties());
final String contextName = file.getName(); properties.putAll(app.getProperties());
// Resource aliases (after getting name) to ensure baseResource is not an alias
if (resource.isAlias())
{
file = new File(resource.getAlias()).toPath().toRealPath().toFile();
resource = Resource.newResource(file);
if (!resource.exists())
throw new IllegalStateException("App resource does not exist " + resource);
}
// Handle a context XML file // Handle a context XML file
if (resource.exists() && FileID.isXmlFile(file)) if (FileID.isXmlFile(file))
{ {
XmlConfiguration xmlc = new XmlConfiguration(resource) XmlConfiguration xmlc = new XmlConfiguration(file, null, properties)
{ {
@Override @Override
public void initializeDefaults(Object context) public void initializeDefaults(Object context)
{ {
super.initializeDefaults(context); super.initializeDefaults(context);
ContextProvider.this.initializeContextHandler(context, file, properties);
// If the XML created object is a ContextHandler
if (context instanceof ContextHandler contextHandler)
{
initializeWebAppContextDefaults(contextHandler);
initializeContextPath(contextHandler, contextName, true);
// TODO look for associated WAR file or directory
// TODO if it is a WAR file, then perhaps unpack it
// TODO set as default baseResource
}
} }
}; };
xmlc.getIdMap().put("Environment", environment); xmlc.getIdMap().put("Environment", environment);
getDeploymentManager().scope(xmlc, resource); xmlc.setJettyStandardIdsAndProperties(getDeploymentManager().getServer(), file);
if (getConfigurationManager() != null)
xmlc.getProperties().putAll(getConfigurationManager().getProperties());
Object context = xmlc.configure(); Object context = xmlc.configure();
if (context instanceof ContextHandler contextHandler) if (context instanceof ContextHandler contextHandler)
@ -367,24 +376,10 @@ public class ContextProvider extends ScanningAppProvider
Class<?> contextHandlerClass = Loader.loadClass(contextHandlerClassName); Class<?> contextHandlerClass = Loader.loadClass(contextHandlerClassName);
if (contextHandlerClass == null) if (contextHandlerClass == null)
throw new IllegalStateException("Unknown ContextHandler class " + contextHandlerClassName + " for " + app); throw new IllegalStateException("Unknown ContextHandler class " + contextHandlerClassName + " for " + app);
ContextHandler contextHandler;
if (Supplier.class.isAssignableFrom(contextHandlerClass))
{
@SuppressWarnings("unchecked")
Supplier<ContextHandler> provider = (Supplier<ContextHandler>)contextHandlerClass.getDeclaredConstructor().newInstance();
contextHandler = provider.get();
}
else
{
contextHandler = (ContextHandler)contextHandlerClass.getDeclaredConstructor().newInstance();
}
initializeWebAppContextDefaults(contextHandler);
initializeContextPath(contextHandler, contextName, !file.isDirectory());
// TODO unpack here (after temp directory is known) Object context = contextHandlerClass.getDeclaredConstructor().newInstance();
contextHandler.setBaseResource(Resource.newResource(file.getAbsoluteFile())); properties.put(Deployable.WAR, file.getCanonicalPath());
return initializeContextHandler(context, file, properties);
return contextHandler;
} }
finally finally
{ {
@ -392,13 +387,10 @@ public class ContextProvider extends ScanningAppProvider
} }
} }
protected void initializeContextPath(ContextHandler context, String contextName, boolean stripExtension) protected void initializeContextPath(ContextHandler context, String contextName)
{ {
String contextPath = contextName;
// Strip any 3 char extension from non directories // Strip any 3 char extension from non directories
if (stripExtension && contextPath.length() > 4 && contextPath.charAt(contextPath.length() - 4) == '.') String contextPath = FileID.getDot3Basename(contextName);
contextPath = contextPath.substring(0, contextPath.length() - 4);
// Ensure "/" is Not Trailing in context paths. // Ensure "/" is Not Trailing in context paths.
if (contextPath.endsWith("/") && contextPath.length() > 1) if (contextPath.endsWith("/") && contextPath.length() > 1)
@ -566,90 +558,4 @@ public class ContextProvider extends ScanningAppProvider
super.fileRemoved(filename); super.fileRemoved(filename);
} }
public Resource unpack(Resource resourceBase) throws IOException
{
// Accept aliases for WAR files
if (resourceBase.isAlias())
{
if (LOG.isDebugEnabled())
LOG.debug("{} anti-aliased to {}", resourceBase, resourceBase.getAlias());
URI alias = resourceBase.getAlias();
resourceBase.close();
resourceBase = Resource.newResource(alias);
}
if (!isExtract() || resourceBase.isDirectory() || resourceBase.getFile() == null)
return resourceBase;
// is the extension a known extension
if (!resourceBase.getFile().getName().toLowerCase().endsWith(".war") &&
!resourceBase.getFile().getName().toLowerCase().endsWith(".jar"))
return resourceBase;
// Track the original web_app Resource, as this could be a PathResource.
// Later steps force the Resource to be a JarFileResource, which introduces
// URLConnection caches in such a way that it prevents Hot Redeployment
// on MS Windows.
Resource originalResource = resourceBase;
// Look for unpacked directory
Path path = resourceBase.getPath();
String name = path.getName(path.getNameCount() - 1).toString();
name = name.substring(0, name.length() - 4);
Path directory = path.getParent(); // TODO support unpacking to temp or work directory
File unpacked = directory.resolve(name).toFile();
File extractLock = directory.resolve(".extract_lock").toFile();
if (!Files.isWritable(directory))
{
LOG.warn("!Writable {} -> {}", resourceBase, directory);
return resourceBase;
}
// Does the directory already exist and is newer than the packed file?
if (unpacked.exists())
{
// If it is not a directory, then we can't unpack
if (!unpacked.isDirectory())
{
LOG.warn("Unusable {} -> {}", resourceBase, unpacked);
return resourceBase;
}
// If it is newer than the resource base and there is no partial extraction, then use it.
if (Files.getLastModifiedTime(directory).toMillis() >= resourceBase.lastModified() && !extractLock.exists())
{
if (LOG.isDebugEnabled())
LOG.debug("Reuse {} -> {}", resourceBase, unpacked);
resourceBase.close();
return Resource.newResource(unpacked);
}
extractLock.createNewFile();
IO.delete(unpacked);
}
else
{
extractLock.createNewFile();
}
if (!unpacked.mkdir())
{
LOG.warn("Cannot Create {} -> {}", resourceBase, unpacked);
extractLock.delete();
return resourceBase;
}
LOG.debug("Unpack {} -> {}", resourceBase, unpacked);
try (Resource jar = JarResource.newJarResource(resourceBase))
{
jar.copyTo(unpacked);
}
extractLock.delete();
resourceBase.close();
return Resource.newResource(unpacked);
}
} }

View File

@ -32,6 +32,7 @@ import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.annotation.ManagedOperation; import org.eclipse.jetty.util.annotation.ManagedOperation;
import org.eclipse.jetty.util.component.ContainerLifeCycle; import org.eclipse.jetty.util.component.ContainerLifeCycle;
import org.eclipse.jetty.util.component.Environment;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -49,7 +50,7 @@ public abstract class ScanningAppProvider extends ContainerLifeCycle implements
private int _scanInterval = 10; private int _scanInterval = 10;
private Scanner _scanner; private Scanner _scanner;
private boolean _useRealPaths; private boolean _useRealPaths;
private String _defaultEnvironment = "ee9"; // TODO null or ee10? private String _environmentName;
private final Scanner.DiscreteListener _scannerListener = new Scanner.DiscreteListener() private final Scanner.DiscreteListener _scannerListener = new Scanner.DiscreteListener()
{ {
@ -83,14 +84,15 @@ public abstract class ScanningAppProvider extends ContainerLifeCycle implements
addBean(_appMap); addBean(_appMap);
} }
public String getDefaultEnvironment() @Override
public String getEnvironmentName()
{ {
return _defaultEnvironment; return _environmentName;
} }
public void setDefaultEnvironment(String defaultEnvironment) public void setEnvironmentName(String environmentName)
{ {
_defaultEnvironment = defaultEnvironment; _environmentName = environmentName;
} }
/** /**
@ -135,10 +137,17 @@ public abstract class ScanningAppProvider extends ContainerLifeCycle implements
*/ */
protected App createApp(String filename) protected App createApp(String filename)
{ {
// TODO otherways to work out the environment???? App app = new App(_deploymentManager, this, filename);
String environment = getDefaultEnvironment();
return new App(_deploymentManager, this, environment, filename); // Only deploy apps for this environment
if (app.getEnvironmentName().equals(getEnvironmentName()))
return app;
boolean appProvider4env = _deploymentManager.getAppProviders().stream()
.map(AppProvider::getEnvironmentName).anyMatch(app.getEnvironmentName()::equals);
if (!appProvider4env)
LOG.warn("No AppProvider with environment {} for {}", app.getEnvironmentName(), app);
return null;
} }
@Override @Override
@ -148,8 +157,19 @@ public abstract class ScanningAppProvider extends ContainerLifeCycle implements
LOG.debug("{}.doStart()", this.getClass().getSimpleName()); LOG.debug("{}.doStart()", this.getClass().getSimpleName());
if (_monitored.size() == 0) if (_monitored.size() == 0)
throw new IllegalStateException("No configuration dir specified"); throw new IllegalStateException("No configuration dir specified");
if (_environmentName == null)
{
List<Environment> nonCore = Environment.getAll().stream().filter(environment -> !environment.equals(Environment.CORE)).toList();
if (nonCore.size() != 1)
throw new IllegalStateException("No environment configured");
_environmentName = nonCore.get(0).getName();
}
LOG.info("Deployment monitor {}", _monitored); Environment environment = Environment.get(_environmentName);
if (environment == null)
throw new IllegalStateException("Unknown environment " + _environmentName);
LOG.info("Deployment monitor {} in {} at intervals {}s", getEnvironmentName(), _monitored, getScanInterval());
List<File> files = new ArrayList<>(); List<File> files = new ArrayList<>();
for (Resource resource : _monitored) for (Resource resource : _monitored)
{ {
@ -191,9 +211,10 @@ public abstract class ScanningAppProvider extends ContainerLifeCycle implements
protected void fileAdded(String filename) throws Exception protected void fileAdded(String filename) throws Exception
{ {
if (LOG.isDebugEnabled())
LOG.debug("added {}", filename);
App app = ScanningAppProvider.this.createApp(filename); App app = ScanningAppProvider.this.createApp(filename);
if (LOG.isDebugEnabled())
LOG.debug("fileAdded {}: {}", filename, app);
if (app != null) if (app != null)
{ {
_appMap.put(filename, app); _appMap.put(filename, app);
@ -203,14 +224,12 @@ public abstract class ScanningAppProvider extends ContainerLifeCycle implements
protected void fileChanged(String filename) throws Exception protected void fileChanged(String filename) throws Exception
{ {
App oldApp = _appMap.remove(filename);
if (oldApp != null)
_deploymentManager.removeApp(oldApp);
App app = ScanningAppProvider.this.createApp(filename);
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("changed {}", filename); LOG.debug("fileChanged {}: {}", filename, app);
App app = _appMap.remove(filename);
if (app != null)
{
_deploymentManager.removeApp(app);
}
app = ScanningAppProvider.this.createApp(filename);
if (app != null) if (app != null)
{ {
_appMap.put(filename, app); _appMap.put(filename, app);
@ -220,9 +239,9 @@ public abstract class ScanningAppProvider extends ContainerLifeCycle implements
protected void fileRemoved(String filename) throws Exception protected void fileRemoved(String filename) throws Exception
{ {
if (LOG.isDebugEnabled())
LOG.debug("removed {}", filename);
App app = _appMap.remove(filename); App app = _appMap.remove(filename);
if (LOG.isDebugEnabled())
LOG.debug("fileRemoved {}: {}", filename, app);
if (app != null) if (app != null)
_deploymentManager.removeApp(app); _deploymentManager.removeApp(app);
} }

View File

@ -22,41 +22,18 @@ import java.util.Locale;
*/ */
public class FileID public class FileID
{ {
/**
* Is the path a Web Archive?
*
* @param path the path to test.
* @return True if a .war or .jar or exploded web directory
* @see FileID#isWebArchiveFile(File)
*/
public static boolean isWebArchive(File path)
{
if (path.isFile())
{
String name = path.getName().toLowerCase(Locale.ENGLISH);
return (name.endsWith(".war") || name.endsWith(".jar"));
}
File webInf = new File(path, "WEB-INF");
File webXml = new File(webInf, "web.xml");
return webXml.exists() && webXml.isFile();
}
/** /**
* Is the path a Web Archive File (not directory) * Is the path a Web Archive File (not directory)
* *
* @param path the path to test. * @param file the path to test.
* @return True if a .war or .jar file. * @return True if a .war or .jar file.
* @see FileID#isWebArchive(File)
*/ */
public static boolean isWebArchiveFile(File path) public static boolean isWebArchiveFile(File file)
{ {
if (!path.isFile()) if (!file.isFile())
{
return false; return false;
}
String name = path.getName().toLowerCase(Locale.ENGLISH); String name = file.getName().toLowerCase(Locale.ENGLISH);
return (name.endsWith(".war") || name.endsWith(".jar")); return (name.endsWith(".war") || name.endsWith(".jar"));
} }
@ -70,4 +47,16 @@ public class FileID
String name = path.getName().toLowerCase(Locale.ENGLISH); String name = path.getName().toLowerCase(Locale.ENGLISH);
return name.endsWith(".xml"); return name.endsWith(".xml");
} }
/**
* Remove any 3 character suffix (e.g. ".war") from a path
* @param path The string path
* @return The path without the suffix or the original path
*/
public static String getDot3Basename(String path)
{
if (path == null || path.length() <= 4 || path.charAt(path.length() - 4) != '.')
return path;
return path.substring(0, path.length() - 4);
}
} }

View File

@ -20,10 +20,14 @@ import org.eclipse.jetty.deploy.test.XmlConfiguredJetty;
import org.eclipse.jetty.server.handler.ContextHandlerCollection; import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir; import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension; import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
import org.eclipse.jetty.util.component.Environment;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.ExtendWith;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
@ -77,6 +81,57 @@ public class DeploymentManagerTest
assertEquals(1, deploybindings.size(), "'deploying' Bindings.size"); assertEquals(1, deploybindings.size(), "'deploying' Bindings.size");
} }
@Test
public void testDefaultEnvironment()
{
DeploymentManager depman = new DeploymentManager();
assertThat(depman.getDefaultEnvironmentName(), Matchers.nullValue());
Environment.ensure("ee7");
depman.addAppProvider(new MockAppProvider()
{
@Override
public String getEnvironmentName()
{
return "ee7";
}
});
assertThat(depman.getDefaultEnvironmentName(), is("ee7"));
Environment.ensure("ee12");
depman.addAppProvider(new MockAppProvider()
{
@Override
public String getEnvironmentName()
{
return "ee12";
}
});
assertThat(depman.getDefaultEnvironmentName(), is("ee12"));
Environment.ensure("ee10");
depman.addAppProvider(new MockAppProvider()
{
@Override
public String getEnvironmentName()
{
return "ee12";
}
});
assertThat(depman.getDefaultEnvironmentName(), is("ee12"));
Environment.ensure("somethingElse");
depman.addAppProvider(new MockAppProvider()
{
@Override
public String getEnvironmentName()
{
return "ee12";
}
});
assertThat(depman.getDefaultEnvironmentName(), is("ee12"));
}
@Test @Test
@Disabled // TODO @Disabled // TODO
public void testXmlConfigured() throws Exception public void testXmlConfigured() throws Exception

View File

@ -20,12 +20,19 @@ import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.component.Environment;
public class MockAppProvider extends AbstractLifeCycle implements AppProvider public class MockAppProvider extends AbstractLifeCycle implements AppProvider
{ {
private DeploymentManager deployMan; private DeploymentManager deployMan;
private File webappsDir; private File webappsDir;
@Override
public String getEnvironmentName()
{
return Environment.ensure("mock").getName();
}
@Override @Override
public void setDeploymentManager(DeploymentManager deploymentManager) public void setDeploymentManager(DeploymentManager deploymentManager)
{ {
@ -40,7 +47,7 @@ public class MockAppProvider extends AbstractLifeCycle implements AppProvider
public void findWebapp(String name) public void findWebapp(String name)
{ {
App app = new App(deployMan, this, null, "mock-" + name); App app = new App(deployMan, this, "mock-" + name);
this.deployMan.addApp(app); this.deployMan.addApp(app);
} }

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-core</artifactId>
<version>12.0.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>jetty-ee</artifactId>
<name>Jetty Core :: EE Utility Classes</name>
<properties>
<bundle-symbolic-name>${project.groupId}.ee</bundle-symbolic-name>
<spotbugs.onlyAnalyze>org.eclipse.jetty.ee.*</spotbugs.onlyAnalyze>
</properties>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<argLine>
@{argLine} ${jetty.surefire.argLine} --add-reads org.eclipse.jetty.io=org.eclipse.jetty.logging
</argLine>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-io</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jmx</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-slf4j-impl</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-test-helper</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -11,16 +11,14 @@
// ======================================================================== // ========================================================================
// //
package org.eclipse.jetty.deploy; module org.eclipse.jetty.ee
import java.util.Map;
/**
* ConfigurationManager
*
* Type for allow injection of property values for replacement in jetty xml files during deployment.
*/
public interface ConfigurationManager
{ {
public Map<String, String> getProperties(); requires org.slf4j;
requires transitive org.eclipse.jetty.io;
// Only required if using JMX.
requires static org.eclipse.jetty.jmx;
exports org.eclipse.jetty.ee;
} }

View File

@ -0,0 +1,56 @@
//
// ========================================================================
// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.ee;
import java.util.Comparator;
import java.util.Map;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public interface Deployable
{
Pattern EE_ENVIRONMENT_NAME_PATTERN = Pattern.compile("ee(\\d*)");
Predicate<String> EE_ENVIRONMENT_NAME = s -> EE_ENVIRONMENT_NAME_PATTERN.matcher(s).matches();
Comparator<String> EE_ENVIRONMENT_COMPARATOR = (e1, e2) ->
{
Matcher m1 = EE_ENVIRONMENT_NAME_PATTERN.matcher(e1);
Matcher m2 = EE_ENVIRONMENT_NAME_PATTERN.matcher(e2);
if (m1.matches() && m2.matches())
{
int n1 = Integer.parseInt(m1.group(1));
int n2 = Integer.parseInt(m2.group(1));
return Integer.compare(n1, n2);
}
return 0;
};
String ENVIRONMENT = "environment";
String WAR = "jetty.deploy.war";
String BASE_TEMP_DIR = "jetty.deploy.tempDir";
String CONFIGURATION_CLASSES = "jetty.deploy.configurationClasses";
String CONTAINER_SCAN_JARS = "jetty.deploy.containerScanJarPattern";
String DEFAULTS_DESCRIPTOR = "jetty.deploy.defaultsDescriptor";
String EXTRACT_WARS = "jetty.deploy.extractWars";
String PARENT_LOADER_PRIORITY = "jetty.deploy.parentLoaderPriority";
String SCI_EXCLUSION_PATTERN = "jetty.deploy.servletContainerInitializerExclusionPattern";
String SCI_ORDER = "jetty.deploy.servletContainerInitializerOrder";
String WEBINF_SCAN_JARS = "jetty.deploy.webInfScanJarPattern";
void initializeDefaults(Map<String, String> properties);
}

View File

@ -19,6 +19,7 @@ lib/jetty-server-${jetty.version}.jar
lib/jetty-xml-${jetty.version}.jar lib/jetty-xml-${jetty.version}.jar
lib/jetty-util-${jetty.version}.jar lib/jetty-util-${jetty.version}.jar
lib/jetty-io-${jetty.version}.jar lib/jetty-io-${jetty.version}.jar
lib/jetty-ee-${jetty.version}.jar
[xml] [xml]
etc/jetty.xml etc/jetty.xml

View File

@ -13,6 +13,8 @@
package org.eclipse.jetty.xml; package org.eclipse.jetty.xml;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
@ -157,7 +159,7 @@ public class XmlConfiguration
* @param server The Server object to set * @param server The Server object to set
* @param webapp The webapps Resource * @param webapp The webapps Resource
*/ */
public void setJettyStandardIdsAndProperties(Object server, Resource webapp) public void setJettyStandardIdsAndProperties(Object server, File webapp)
{ {
try try
{ {
@ -174,7 +176,7 @@ public class XmlConfiguration
if (webapp != null) if (webapp != null)
{ {
Path webappPath = webapp.getFile().toPath().toAbsolutePath(); Path webappPath = webapp.toPath().toAbsolutePath();
getProperties().put("jetty.webapp", webappPath.toString()); getProperties().put("jetty.webapp", webappPath.toString());
getProperties().put("jetty.webapps", webappPath.getParent().toString()); getProperties().put("jetty.webapps", webappPath.getParent().toString());
getProperties().put("jetty.webapps.uri", normalizeURI(webappPath.getParent().toUri().toString())); getProperties().put("jetty.webapps.uri", normalizeURI(webappPath.getParent().toUri().toString()));
@ -193,8 +195,8 @@ public class XmlConfiguration
return uri; return uri;
} }
private final Map<String, Object> _idMap = new HashMap<>(); private final Map<String, Object> _idMap;
private final Map<String, String> _propertyMap = new HashMap<>(); private final Map<String, String> _propertyMap;
private final Resource _location; private final Resource _location;
private final String _dtd; private final String _dtd;
private ConfigurationProcessor _processor; private ConfigurationProcessor _processor;
@ -216,11 +218,27 @@ public class XmlConfiguration
*/ */
public XmlConfiguration(Resource resource) throws SAXException, IOException public XmlConfiguration(Resource resource) throws SAXException, IOException
{ {
try (ConfigurationParser parser = getParser(); InputStream inputStream = resource.getInputStream()) this(resource.getFile(), null, null);
}
/**
* Reads and parses the XML configuration file.
*
* @param file the XML configuration
* @param idMap Map of objects with IDs
* @param properties Map of properties
* @throws IOException if the configuration could not be read
* @throws SAXException if the configuration could not be parsed
*/
public XmlConfiguration(File file, Map<String, Object> idMap, Map<String, String> properties) throws SAXException, IOException
{
try (ConfigurationParser parser = getParser(); InputStream inputStream = new FileInputStream(file))
{ {
_location = resource; _location = Resource.newResource(file);
setConfig(parser.parse(inputStream)); setConfig(parser.parse(inputStream));
_dtd = parser.getDTD(); _dtd = parser.getDTD();
_idMap = idMap == null ? new HashMap<>() : idMap;
_propertyMap = properties == null ? new HashMap<>() : properties;
} }
} }

View File

@ -1609,7 +1609,7 @@ public class XmlConfigurationTest
" </Set>" + " </Set>" +
"</Configure>"); "</Configure>");
configuration.setJettyStandardIdsAndProperties(null, Resource.newResource(war)); configuration.setJettyStandardIdsAndProperties(null, war.toFile());
TestConfiguration tc = new TestConfiguration(); TestConfiguration tc = new TestConfiguration();
configuration.configure(tc); configuration.configure(tc);
@ -1724,7 +1724,7 @@ public class XmlConfigurationTest
try try
{ {
configuration.setJettyStandardIdsAndProperties(null, Resource.newResource(war)); configuration.setJettyStandardIdsAndProperties(null, war.toFile());
configuration.getProperties().put("jetty.base", jettyBasePath); configuration.getProperties().put("jetty.base", jettyBasePath);
if (configValue != null) if (configValue != null)
configuration.getProperties().put("jetty.sslContext.keyStorePath", configValue); configuration.getProperties().put("jetty.sslContext.keyStorePath", configValue);

View File

@ -16,6 +16,7 @@
<module>jetty-bom</module> <module>jetty-bom</module>
<module>jetty-client</module> <module>jetty-client</module>
<module>jetty-deploy</module> <module>jetty-deploy</module>
<module>jetty-ee</module>
<module>jetty-fcgi</module> <module>jetty-fcgi</module>
<module>jetty-http</module> <module>jetty-http</module>
<module>jetty-http2</module> <module>jetty-http2</module>

View File

@ -14,5 +14,5 @@ webapp
ee10-deploy ee10-deploy
[files] [files]
maven://org.eclipse.jetty.ee10.demos/ee10-demo-async-rest-webapp/${jetty.version}/war|webapps-ee10/ee10-demo-async-rest.war maven://org.eclipse.jetty.ee10.demos/jetty-ee10-demo-async-rest-webapp/${jetty.version}/war|webapps/ee10-demo-async-rest.war

View File

@ -19,10 +19,10 @@ ee10-annotations
ext ext
[files] [files]
basehome:modules/demo.d/ee10-demo-jaas.xml|webapps-ee10/ee10-demo-jaas.xml basehome:modules/demo.d/ee10-demo-jaas.xml|webapps/ee10-demo-jaas.xml
basehome:modules/demo.d/ee10-demo-login.conf|etc/ee10-demo-login.conf basehome:modules/demo.d/ee10-demo-login.conf|etc/ee10-demo-login.conf
basehome:modules/demo.d/ee10-demo-login.properties|etc/ee10-demo-login.properties basehome:modules/demo.d/ee10-demo-login.properties|etc/ee10-demo-login.properties
maven://org.eclipse.jetty.ee10.demos/ee10-demo-jaas-webapp/${jetty.version}/war|webapps-ee10/ee10-demo-jaas.war maven://org.eclipse.jetty.ee10.demos/jetty-ee10-demo-jaas-webapp/${jetty.version}/war|webapps/ee10-demo-jaas.war
[ini] [ini]
# Enable security via jaas, and configure it # Enable security via jaas, and configure it

View File

@ -24,6 +24,6 @@ ee10-demo-realm
[files] [files]
webapps-ee10/ee10-demo-jetty.d/ webapps-ee10/ee10-demo-jetty.d/
basehome:modules/demo.d/ee10-demo-jetty.xml|webapps-ee10/ee10-demo-jetty.xml basehome:modules/demo.d/ee10-demo-jetty.xml|webapps/ee10-demo-jetty.xml
basehome:modules/demo.d/ee10-demo-jetty-override-web.xml|webapps-ee10/ee10-demo-jetty.d/ee10-demo-jetty-override-web.xml basehome:modules/demo.d/ee10-demo-jetty-override-web.xml|webapps/ee10-demo-jetty.d/ee10-demo-jetty-override-web.xml
maven://org.eclipse.jetty.ee10.demos/ee10-demo-jetty-webapp/${jetty.version}/war|webapps-ee10/ee10-demo-jetty.war maven://org.eclipse.jetty.ee10.demos/jetty-ee10-demo-jetty-webapp/${jetty.version}/war|webapps/ee10-demo-jetty.war

View File

@ -10,5 +10,5 @@ demo
ee10-deploy ee10-deploy
[files] [files]
basehome:modules/demo.d/ee10-demo-moved-context.xml|webapps-ee10/ee10-demo-moved-context.xml basehome:modules/demo.d/ee10-demo-moved-context.xml|webapps/ee10-demo-moved-context.xml

View File

@ -18,6 +18,6 @@ ee10-plus
ee10-demo-mock-resources ee10-demo-mock-resources
[files] [files]
basehome:modules/demo.d/ee10-demo-jndi.xml|webapps-ee10/ee10-demo-jndi.xml basehome:modules/demo.d/ee10-demo-jndi.xml|webapps/ee10-demo-jndi.xml
maven://org.eclipse.jetty.ee10.demos/ee10-demo-jndi-webapp/${jetty.version}/war|webapps-ee10/ee10-demo-jndi.war maven://org.eclipse.jetty.ee10.demos/jetty-ee10-demo-jndi-webapp/${jetty.version}/war|webapps/ee10-demo-jndi.war
maven://jakarta.mail/jakarta.mail-api/2.0.0/jar|lib/ext/jakarta.mail-api-2.0.0.jar maven://jakarta.mail/jakarta.mail-api/2.0.0/jar|lib/ext/jakarta.mail-api-2.0.0.jar

View File

@ -14,4 +14,4 @@ ee10-jstl
ee10-deploy ee10-deploy
[files] [files]
maven://org.eclipse.jetty.ee10.demos/ee10-demo-jsp-webapp/${jetty.version}/war|webapps-ee10/ee10-demo-jsp.war maven://org.eclipse.jetty.ee10.demos/jetty-ee10-demo-jsp-webapp/${jetty.version}/war|webapps/ee10-demo-jsp.war

View File

@ -18,7 +18,7 @@
<artifactId>maven-bundle-plugin</artifactId> <artifactId>maven-bundle-plugin</artifactId>
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>org.eclipse.jetty.demos.demo-mock-resources</Bundle-SymbolicName> <Bundle-SymbolicName>org.eclipse.jetty.ee10.demos.demo-mock-resources</Bundle-SymbolicName>
<Bundle-Description>Mock resources used for testing</Bundle-Description> <Bundle-Description>Mock resources used for testing</Bundle-Description>
<Export-Package> <Export-Package>
org.example;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}" org.example;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"

View File

@ -17,4 +17,4 @@ ee10-annotations
lib/ee10-demo-mock-resources-${jetty.version}.jar lib/ee10-demo-mock-resources-${jetty.version}.jar
[files] [files]
maven://org.eclipse.jetty.ee10.demos/ee10-demo-mock-resources/${jetty.version}/jar|lib/ee10-demo-mock-resources-${jetty.version}.jar maven://org.eclipse.jetty.ee10.demos/jetty-ee10-demo-mock-resources/${jetty.version}/jar|lib/ee10-demo-mock-resources-${jetty.version}.jar

View File

@ -14,4 +14,4 @@ webapp
ee10-deploy ee10-deploy
[files] [files]
maven://org.eclipse.jetty.ee10.demos/ee10-demo-proxy-webapp/${jetty.version}/war|webapps-ee10/ee10-demo-proxy.war maven://org.eclipse.jetty.ee10.demos/jetty-ee10-demo-proxy-webapp/${jetty.version}/war|webapps/ee10-demo-proxy.war

View File

@ -12,4 +12,4 @@ webapp
ee10-deploy ee10-deploy
[files] [files]
maven://org.eclipse.jetty.ee10.demos/ee10-demo-simple-webapp/${jetty.version}/war|webapps-ee10/ee10-demo-simple.war maven://org.eclipse.jetty.ee10.demos/jetty-ee10-demo-simple-webapp/${jetty.version}/war|webapps/ee10-demo-simple.war

View File

@ -20,7 +20,7 @@
<extensions>true</extensions> <extensions>true</extensions>
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>org.eclipse.jetty.demos.demo-servlet-container-initializer;singleton:=true</Bundle-SymbolicName> <Bundle-SymbolicName>org.eclipse.jetty.ee10.demos.demo-servlet-container-initializer;singleton:=true</Bundle-SymbolicName>
<Bundle-Description>A bundle containing a ServletContainerInitializer for testing</Bundle-Description> <Bundle-Description>A bundle containing a ServletContainerInitializer for testing</Bundle-Description>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability> <Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
<Provide-Capability>osgi.serviceloader; osgi.serviceloader=jakarta.servlet.ServletContainerInitializer</Provide-Capability> <Provide-Capability>osgi.serviceloader; osgi.serviceloader=jakarta.servlet.ServletContainerInitializer</Provide-Capability>

View File

@ -20,5 +20,5 @@ ee10-demo-realm
ee10-demo-mock-resources ee10-demo-mock-resources
[files] [files]
basehome:modules/demo.d/ee10-demo-spec.xml|webapps-ee10/ee10-demo-spec.xml basehome:modules/demo.d/ee10-demo-spec.xml|webapps/ee10-demo-spec.xml
maven://org.eclipse.jetty.ee10.demos/ee10-demo-spec-webapp/${jetty.version}/war|webapps-ee10/ee10-demo-spec.war maven://org.eclipse.jetty.ee10.demos/jetty-ee10-demo-spec-webapp/${jetty.version}/war|webapps/ee10-demo-spec.war

View File

@ -350,7 +350,7 @@ public class JettyHomeForker extends AbstractForker
modulesPath = Files.createDirectories(targetBasePath.resolve("modules")); modulesPath = Files.createDirectories(targetBasePath.resolve("modules"));
etcPath = Files.createDirectories(targetBasePath.resolve("etc")); etcPath = Files.createDirectories(targetBasePath.resolve("etc"));
libPath = Files.createDirectories(targetBasePath.resolve("lib")); libPath = Files.createDirectories(targetBasePath.resolve("lib"));
webappPath = Files.createDirectories(targetBasePath.resolve("webapps-ee10")); webappPath = Files.createDirectories(targetBasePath.resolve("webapps"));
mavenLibPath = Files.createDirectories(libPath.resolve("maven-ee10")); mavenLibPath = Files.createDirectories(libPath.resolve("maven-ee10"));
//copy in the jetty-maven-plugin jar //copy in the jetty-maven-plugin jar

View File

@ -48,7 +48,7 @@
<Bundle-SymbolicName>${bundle-symbolic-name}</Bundle-SymbolicName> <Bundle-SymbolicName>${bundle-symbolic-name}</Bundle-SymbolicName>
<Bundle-Name>Jetty OSGi Test WebApp Fragment</Bundle-Name> <Bundle-Name>Jetty OSGi Test WebApp Fragment</Bundle-Name>
<Bundle-RequiredExecutionEnvironment>J2SE-1.5</Bundle-RequiredExecutionEnvironment> <Bundle-RequiredExecutionEnvironment>J2SE-1.5</Bundle-RequiredExecutionEnvironment>
<Fragment-Host>org.eclipse.jetty.demos.spec.webapp</Fragment-Host> <Fragment-Host>org.eclipse.jetty.ee10.demos.spec.webapp</Fragment-Host>
<Jetty-WarFragmentResourcePath>/</Jetty-WarFragmentResourcePath> <Jetty-WarFragmentResourcePath>/</Jetty-WarFragmentResourcePath>
</instructions> </instructions>
</configuration> </configuration>

View File

@ -198,7 +198,6 @@ public class ServletContextHandler extends ContextHandler implements Graceful
private final ServletContextApi _servletContext; private final ServletContextApi _servletContext;
protected ContextStatus _contextStatus = ContextStatus.NOTSET; protected ContextStatus _contextStatus = ContextStatus.NOTSET;
private final Map<String, String> _initParams = new HashMap<>(); private final Map<String, String> _initParams = new HashMap<>();
private boolean _contextPathDefault = true;
private String _defaultRequestCharacterEncoding; private String _defaultRequestCharacterEncoding;
private String _defaultResponseCharacterEncoding; private String _defaultResponseCharacterEncoding;
private String _contextPathEncoded = "/"; private String _contextPathEncoded = "/";
@ -655,19 +654,6 @@ public class ServletContextHandler extends ContextHandler implements Graceful
.toArray(String[]::new); .toArray(String[]::new);
} }
/**
* Set the default context path.
* A default context path may be overriden by a default-context-path element
* in a web.xml
*
* @param contextPath The _contextPath to set.
*/
public void setDefaultContextPath(String contextPath)
{
setContextPath(contextPath);
_contextPathDefault = true;
}
public void setDefaultRequestCharacterEncoding(String encoding) public void setDefaultRequestCharacterEncoding(String encoding)
{ {
_defaultRequestCharacterEncoding = encoding; _defaultRequestCharacterEncoding = encoding;
@ -688,14 +674,6 @@ public class ServletContextHandler extends ContextHandler implements Graceful
return _defaultResponseCharacterEncoding; return _defaultResponseCharacterEncoding;
} }
/**
* @return True if the current contextPath is from default settings
*/
public boolean isContextPathDefault()
{
return _contextPathDefault;
}
/** /**
* @param contextPath The _contextPath to set. * @param contextPath The _contextPath to set.
*/ */
@ -724,7 +702,6 @@ public class ServletContextHandler extends ContextHandler implements Graceful
super.setContextPath(contextPath); super.setContextPath(contextPath);
_contextPathEncoded = URIUtil.encodePath(contextPath); _contextPathEncoded = URIUtil.encodePath(contextPath);
_contextPathDefault = false;
if (getServer() != null && (getServer().isStarting() || getServer().isStarted())) if (getServer() != null && (getServer().isStarting() || getServer().isStarted()))
{ {

View File

@ -102,5 +102,9 @@
<artifactId>jetty-client</artifactId> <artifactId>jetty-client</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-ee</artifactId>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -21,14 +21,14 @@
<Call name="addAppProvider"> <Call name="addAppProvider">
<Arg> <Arg>
<New id="WebAppProvider" class="org.eclipse.jetty.deploy.providers.ContextProvider"> <New id="WebAppProvider" class="org.eclipse.jetty.deploy.providers.ContextProvider">
<Set name="defaultEnvironment">ee10</Set> <Set name="environmentName">ee10</Set>
<Set name="monitoredDirName"> <Set name="monitoredDirName">
<Call name="resolvePath" class="org.eclipse.jetty.xml.XmlConfiguration"> <Call name="resolvePath" class="org.eclipse.jetty.xml.XmlConfiguration">
<Arg> <Arg>
<Property name="jetty.base" /> <Property name="jetty.base" />
</Arg> </Arg>
<Arg> <Arg>
<Property name="jetty.deploy.monitoredDir" default="webapps-ee10" /> <Property name="jetty.deploy.monitoredDir" default="webapps" />
</Arg> </Arg>
</Call> </Call>
</Set> </Set>
@ -40,22 +40,28 @@
</Default> </Default>
</Property> </Property>
</Set> </Set>
<Set name="scanInterval"> <Set name="scanInterval" property="jetty.deploy.scanInterval"/>
<Property name="jetty.deploy.scanInterval" default="1" /> <Set name="defaultsDescriptor" property="jetty.deploy.defaultsDescriptor"/>
</Set> <Set name="extractWars" property="jetty.deploy.extractWars" />
<Set name="extractWars"> <Set name="parentLoaderPriority" property="jetty.deploy.parentLoaderPriority" />
<Property name="jetty.deploy.extractWars" default="true" /> <Set name="configurationClasses" property="jetty.deploy.configurationClasses" />
</Set> <Set name="tempDir" property="jetty.deploy.tempDir" />
<Set name="configurationManager"> <Get name="properties">
<New class="org.eclipse.jetty.deploy.PropertiesConfigurationManager"> <Put name="jetty.deploy.containerScanJarPattern">
<!-- file of context configuration properties <Property name="jetty.deploy.containerScanJarPattern">
<Set name="file"><SystemProperty name="jetty.base"/>/etc/some.properties</Set> <Default>.*jakarta.servlet.jsp.jstl-.*\.jar$</Default>
--> </Property>
<!-- set a context configuration property </Put>
<Call name="put"><Arg>name</Arg><Arg>value</Arg></Call> <Put name="jetty.deploy.webInfScanJarPattern">
--> <Property name="jetty.deploy.webInfScanJarPattern"/>
</New> </Put>
</Set> <Put name="jetty.deploy.servletContainerInitializerExclusionPattern">
<Property name="jetty.deploy.servletContainerInitializerExclusionPattern"/>
</Put>
<Put name="jetty.deploy.servletContainerInitializerOrder">
<Property name="jetty.deploy.servletContainerInitializerOrder"/>
</Put>
</Get>
</New> </New>
</Arg> </Arg>
</Call> </Call>

View File

@ -11,23 +11,44 @@ ee10-webapp
[lib] [lib]
[files] [files]
webapps-ee10/ webapps/
[xml] [xml]
etc/jetty-ee10-deploy.xml etc/jetty-ee10-deploy.xml
[ini-template] [ini-template]
# Monitored directory name (relative to $jetty.base) ## Monitored directory name (relative to $jetty.base)
# jetty.deploy.monitoredDir=webapps-ee10 # jetty.deploy.monitoredDir=webapps
# - OR - ## - OR -
# Monitored directory path (fully qualified) ## Monitored directory path (fully qualified)
# jetty.deploy.monitoredPath=/var/www/webapps-ee10 # jetty.deploy.monitoredPath=/var/www/webapps
# Defaults Descriptor for all deployed webapps ## Defaults Descriptor for all deployed webapps
# jetty.deploy.defaultsDescriptorPath=${jetty.base}/etc/webdefault-ee10.xml # jetty.deploy.defaultsDescriptor=${jetty.base}/etc/webdefault-ee10.xml
# Monitored directory scan period (seconds) ## Monitored directory scan period (seconds)
# jetty.deploy.scanInterval=1 # jetty.deploy.scanInterval=1
# Whether to extract *.war files ## Whether to extract *.war files
# jetty.deploy.extractWars=true # jetty.deploy.extractWars=true
## Whether to give the parent classloader priority
# jetty.deploy.parentLoaderPriority=true
## Comma separated list of configuration classes to set.
# jetty.deploy.configurationClasses=
## Base temporary directory for deployed web applications.
# jetty.deploy.tempDir=
## Pattern to select jars from the container classloader to be scanned (or null to scan no jars)
# jetty.deploy.containerScanJarPattern=.*jakarta.servlet.jsp.jstl-.*\.jar$
## Pattern to select jars from the container classloader to be scanned (or null to scan all jars).
# jetty.deploy.webInfScanJarPattern=
## Pattern to exclude discovered ServletContainerInitializers
# jetty.deploy.servletContainerInitializerExclusionPattern=
## Order of discovered ServletContainerInitializers
# jetty.deploy.servletContainerInitializerOrder=

View File

@ -30,6 +30,7 @@ module org.eclipse.jetty.ee10.webapp
requires org.slf4j; requires org.slf4j;
requires transitive java.instrument; requires transitive java.instrument;
requires transitive org.eclipse.jetty.ee;
requires transitive org.eclipse.jetty.session; requires transitive org.eclipse.jetty.session;
requires transitive org.eclipse.jetty.ee10.servlet; requires transitive org.eclipse.jetty.ee10.servlet;
requires transitive org.eclipse.jetty.xml; requires transitive org.eclipse.jetty.xml;

View File

@ -36,7 +36,9 @@ import java.util.jar.JarEntry;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.PatternMatcher; import org.eclipse.jetty.util.PatternMatcher;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.resource.EmptyResource; import org.eclipse.jetty.util.resource.EmptyResource;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceCollection; import org.eclipse.jetty.util.resource.ResourceCollection;
@ -186,13 +188,19 @@ public class MetaInfConfiguration extends AbstractConfiguration
*/ */
public void findAndFilterContainerPaths(final WebAppContext context) throws Exception public void findAndFilterContainerPaths(final WebAppContext context) throws Exception
{ {
String pattern = (String)context.getAttribute(CONTAINER_JAR_PATTERN);
if (LOG.isDebugEnabled())
LOG.debug("{}={}", CONTAINER_JAR_PATTERN, pattern);
if (StringUtil.isBlank(pattern))
return; // TODO review if this short cut will allow later code simplifications
// Apply an initial name filter to the jars to select which will be eventually // Apply an initial name filter to the jars to select which will be eventually
// scanned for META-INF info and annotations. The filter is based on inclusion patterns. // scanned for META-INF info and annotations. The filter is based on inclusion patterns.
ContainerPathNameMatcher containerPathNameMatcher = new ContainerPathNameMatcher(context, (String)context.getAttribute(CONTAINER_JAR_PATTERN)); ContainerPathNameMatcher containerPathNameMatcher = new ContainerPathNameMatcher(context, pattern);
List<URI> containerUris = getAllContainerJars(context); List<URI> containerUris = getAllContainerJars(context);
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
LOG.debug("Matching container urls {}", containerUris); LOG.debug("All container urls {}", containerUris);
containerPathNameMatcher.match(containerUris); containerPathNameMatcher.match(containerUris);
// When running on jvm 9 or above, we we won't be able to look at the application // When running on jvm 9 or above, we we won't be able to look at the application
@ -264,9 +272,12 @@ public class MetaInfConfiguration extends AbstractConfiguration
throws Exception throws Exception
{ {
//Apply filter to WEB-INF/lib jars //Apply filter to WEB-INF/lib jars
WebAppPathNameMatcher matcher = new WebAppPathNameMatcher(context, (String)context.getAttribute(WEBINF_JAR_PATTERN)); String pattern = (String)context.getAttribute(WEBINF_JAR_PATTERN);
WebAppPathNameMatcher matcher = new WebAppPathNameMatcher(context, pattern);
List<Resource> jars = findJars(context); List<Resource> jars = findJars(context);
if (LOG.isDebugEnabled())
LOG.debug("webapp {}={} jars {}", WEBINF_JAR_PATTERN, pattern, jars);
//Convert to uris for matching //Convert to uris for matching
if (jars != null) if (jars != null)
@ -284,23 +295,21 @@ public class MetaInfConfiguration extends AbstractConfiguration
protected List<URI> getAllContainerJars(final WebAppContext context) throws URISyntaxException protected List<URI> getAllContainerJars(final WebAppContext context) throws URISyntaxException
{ {
List<URI> uris = new ArrayList<>(); List<URI> uris = new ArrayList<>();
if (context.getClassLoader() != null) ClassLoader loader = MetaInfConfiguration.class.getClassLoader();
while (loader != null)
{ {
ClassLoader loader = context.getClassLoader().getParent(); if (loader instanceof URLClassLoader)
while (loader != null)
{ {
if (loader instanceof URLClassLoader) URL[] urls = ((URLClassLoader)loader).getURLs();
if (urls != null)
{ {
URL[] urls = ((URLClassLoader)loader).getURLs(); for (URL url : urls)
if (urls != null) uris.add(new URI(url.toString().replaceAll(" ", "%20")));
for (URL url : urls)
{
uris.add(new URI(url.toString().replaceAll(" ", "%20")));
}
} }
loader = loader.getParent();
} }
loader = loader.getParent();
} }
return uris; return uris;
} }

View File

@ -38,10 +38,10 @@ import jakarta.servlet.http.HttpSessionAttributeListener;
import jakarta.servlet.http.HttpSessionBindingListener; import jakarta.servlet.http.HttpSessionBindingListener;
import jakarta.servlet.http.HttpSessionIdListener; import jakarta.servlet.http.HttpSessionIdListener;
import jakarta.servlet.http.HttpSessionListener; import jakarta.servlet.http.HttpSessionListener;
import org.eclipse.jetty.ee.Deployable;
import org.eclipse.jetty.ee10.servlet.ErrorHandler; import org.eclipse.jetty.ee10.servlet.ErrorHandler;
import org.eclipse.jetty.ee10.servlet.ErrorPageErrorHandler; import org.eclipse.jetty.ee10.servlet.ErrorPageErrorHandler;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler; import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler.ServletContextApi;
import org.eclipse.jetty.ee10.servlet.ServletHandler; import org.eclipse.jetty.ee10.servlet.ServletHandler;
import org.eclipse.jetty.ee10.servlet.SessionHandler; import org.eclipse.jetty.ee10.servlet.SessionHandler;
import org.eclipse.jetty.ee10.servlet.security.ConstraintAware; import org.eclipse.jetty.ee10.servlet.security.ConstraintAware;
@ -50,8 +50,8 @@ import org.eclipse.jetty.ee10.servlet.security.ConstraintSecurityHandler;
import org.eclipse.jetty.ee10.servlet.security.SecurityHandler; import org.eclipse.jetty.ee10.servlet.security.SecurityHandler;
import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedObject;
@ -75,7 +75,7 @@ import org.slf4j.LoggerFactory;
* *
*/ */
@ManagedObject("Web Application ContextHandler") @ManagedObject("Web Application ContextHandler")
public class WebAppContext extends ServletContextHandler implements WebAppClassLoader.Context public class WebAppContext extends ServletContextHandler implements WebAppClassLoader.Context, Deployable
{ {
static final Logger LOG = LoggerFactory.getLogger(WebAppContext.class); static final Logger LOG = LoggerFactory.getLogger(WebAppContext.class);
@ -121,6 +121,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
private boolean _logUrlOnStart = false; private boolean _logUrlOnStart = false;
private boolean _parentLoaderPriority = Boolean.getBoolean("org.eclipse.jetty.server.webapp.parentLoaderPriority"); private boolean _parentLoaderPriority = Boolean.getBoolean("org.eclipse.jetty.server.webapp.parentLoaderPriority");
private PermissionCollection _permissions; private PermissionCollection _permissions;
private boolean _defaultContextPath = true;
private String[] _contextWhiteList = null; private String[] _contextWhiteList = null;
@ -228,6 +229,55 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
setParent(parent); setParent(parent);
} }
@Override
public void initializeDefaults(Map<String, String> properties)
{
for (String property : properties.keySet())
{
String value = properties.get(property);
if (LOG.isDebugEnabled())
LOG.debug("init {}: {}", property, value);
switch (property)
{
case Deployable.WAR -> setWar(value);
case Deployable.BASE_TEMP_DIR -> setAttribute(BASETEMPDIR, value);
case Deployable.CONFIGURATION_CLASSES -> setConfigurationClasses(value == null ? null : value.split(","));
case Deployable.CONTAINER_SCAN_JARS -> setAttribute(MetaInfConfiguration.CONTAINER_JAR_PATTERN, value);
case Deployable.EXTRACT_WARS -> setExtractWAR(Boolean.parseBoolean(value));
case Deployable.PARENT_LOADER_PRIORITY -> setParentLoaderPriority(Boolean.parseBoolean(value));
case Deployable.WEBINF_SCAN_JARS -> setAttribute(MetaInfConfiguration.WEBINF_JAR_PATTERN, value);
case Deployable.DEFAULTS_DESCRIPTOR -> setDefaultsDescriptor(value);
case Deployable.SCI_EXCLUSION_PATTERN -> setAttribute("org.eclipse.jetty.containerInitializerExclusionPattern", value);
case Deployable.SCI_ORDER -> setAttribute("org.eclipse.jetty.containerInitializerOrder", value);
default ->
{
if (LOG.isDebugEnabled() && StringUtil.isNotBlank(value))
LOG.debug("unknown property {}={}", property, value);
}
}
}
_defaultContextPath = true;
}
public boolean isContextPathDefault()
{
return _defaultContextPath;
}
@Override
public void setContextPath(String contextPath)
{
super.setContextPath(contextPath);
_defaultContextPath = false;
}
public void setDefaultContextPath(String contextPath)
{
super.setContextPath(contextPath);
_defaultContextPath = true;
}
/** /**
* @param servletContextName The servletContextName to set. * @param servletContextName The servletContextName to set.
*/ */

View File

@ -134,16 +134,17 @@ public class MetaInfConfigurationTest
{ {
MetaInfConfiguration config = new MetaInfConfiguration(); MetaInfConfiguration config = new MetaInfConfiguration();
WebAppContext context = new WebAppContext(); WebAppContext context = new WebAppContext();
context.setAttribute(MetaInfConfiguration.CONTAINER_JAR_PATTERN, ".*/jetty-util-[^/]*\\.jar$|.*/jetty-util/target/classes/$|.*/foo-bar-janb.jar"); context.setAttribute(MetaInfConfiguration.CONTAINER_JAR_PATTERN, ".*servlet-api-[^/]*\\.jar$|.*/foo-bar-janb.jar");
WebAppClassLoader loader = new WebAppClassLoader(context); WebAppClassLoader loader = new WebAppClassLoader(context);
context.setClassLoader(loader); context.setClassLoader(loader);
config.findAndFilterContainerPaths(context); config.findAndFilterContainerPaths(context);
List<Resource> containerResources = context.getMetaData().getContainerResources(); List<Resource> containerResources = context.getMetaData().getContainerResources();
assertEquals(2, containerResources.size()); assertEquals(2, containerResources.size());
for (Resource r : containerResources) for (Resource r : containerResources)
{ {
String s = r.toString(); String s = r.toString();
assertTrue(s.endsWith("foo-bar-janb.jar") || s.contains("jetty-util")); assertTrue(s.endsWith("foo-bar-janb.jar") || s.contains("servlet-api"));
} }
} }
} }

View File

@ -41,7 +41,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-io</artifactId> <artifactId>jetty-ee</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>

View File

@ -21,41 +21,39 @@
<Call name="addAppProvider"> <Call name="addAppProvider">
<Arg> <Arg>
<New id="WebAppProvider" class="org.eclipse.jetty.deploy.providers.ContextProvider"> <New id="WebAppProvider" class="org.eclipse.jetty.deploy.providers.ContextProvider">
<Set name="defaultEnvironment">ee8</Set> <Set name="EnvironmentName">ee8</Set>
<Set name="monitoredDirName"> <Set name="monitoredDirName">
<Call name="resolvePath" class="org.eclipse.jetty.xml.XmlConfiguration"> <Call name="resolvePath" class="org.eclipse.jetty.xml.XmlConfiguration">
<Arg> <Arg>
<Property name="jetty.base" /> <Property name="jetty.base" />
</Arg> </Arg>
<Arg> <Arg>
<Property name="jetty.deploy.monitoredDir" default="webapps-ee8" /> <Property name="jetty.deploy.monitoredDir" default="webapps" />
</Arg> </Arg>
</Call> </Call>
</Set> </Set>
<Set name="defaultsDescriptor"> <Set name="scanInterval" property="jetty.deploy.scanInterval"/>
<Property> <Set name="defaultsDescriptor" property="jetty.deploy.defaultsDescriptor"/>
<Name>jetty.deploy.defaultsDescriptorPath</Name> <Set name="extractWars" property="jetty.deploy.extractWars" />
<Default> <Set name="parentLoaderPriority" property="jetty.deploy.parentLoaderPriority" />
<Property name="jetty.home" default="." />/etc/webdefault-ee8.xml <Set name="configurationClasses" property="jetty.deploy.configurationClasses" />
</Default> <Set name="tempDir" property="jetty.deploy.tempDir" />
</Property> <Get name="properties">
</Set> <Put name="jetty.deploy.containerScanJarPattern">
<Set name="scanInterval"> <Property name="jetty.deploy.containerScanJarPattern">
<Property name="jetty.deploy.scanInterval" default="1" /> <Default>.*jakarta.servlet.jsp.jstl-.*\.jar$</Default>
</Set> </Property>
<Set name="extractWars"> </Put>
<Property name="jetty.deploy.extractWars" default="true" /> <Put name="jetty.deploy.webInfScanJarPattern">
</Set> <Property name="jetty.deploy.webInfScanJarPattern"/>
<Set name="configurationManager"> </Put>
<New class="org.eclipse.jetty.deploy.PropertiesConfigurationManager"> <Put name="jetty.deploy.servletContainerInitializerExclusionPattern">
<!-- file of context configuration properties <Property name="jetty.deploy.servletContainerInitializerExclusionPattern"/>
<Set name="file"><SystemProperty name="jetty.base"/>/etc/some.properties</Set> </Put>
--> <Put name="jetty.deploy.servletContainerInitializerOrder">
<!-- set a context configuration property <Property name="jetty.deploy.servletContainerInitializerOrder"/>
<Call name="put"><Arg>name</Arg><Arg>value</Arg></Call> </Put>
--> </Get>
</New>
</Set>
</New> </New>
</Arg> </Arg>
</Call> </Call>

View File

@ -11,23 +11,44 @@ ee8-webapp
[lib] [lib]
[files] [files]
webapps-ee8/ webapps/
[xml] [xml]
etc/jetty-ee8-deploy.xml etc/jetty-ee8-deploy.xml
[ini-template] [ini-template]
# Monitored directory name (relative to $jetty.base) ## Monitored directory name (relative to $jetty.base)
# jetty.deploy.monitoredDir=webapps-ee8 # jetty.deploy.monitoredDir=webapps
# - OR - ## - OR -
# Monitored directory path (fully qualified) ## Monitored directory path (fully qualified)
# jetty.deploy.monitoredPath=/var/www/webapps-ee8 # jetty.deploy.monitoredPath=/var/www/webapps
# Defaults Descriptor for all deployed webapps ## Defaults Descriptor for all deployed webapps
# jetty.deploy.defaultsDescriptorPath=${jetty.base}/etc/webdefault-ee8.xml # jetty.deploy.defaultsDescriptor=${jetty.base}/etc/webdefault-ee8.xml
# Monitored directory scan period (seconds) ## Monitored directory scan period (seconds)
# jetty.deploy.scanInterval=1 # jetty.deploy.scanInterval=1
# Whether to extract *.war files ## Whether to extract *.war files
# jetty.deploy.extractWars=true # jetty.deploy.extractWars=true
## Whether to give the parent classloader priority
# jetty.deploy.parentLoaderPriority=true
## Comma separated list of configuration classes to set.
# jetty.deploy.configurationClasses=
## Base temporary directory for deployed web applications.
# jetty.deploy.tempDir=
## Pattern to select jars from the container classloader to be scanned (or null to scan no jars)
# jetty.deploy.containerScanJarPattern=.*jakarta.servlet.jsp.jstl-.*\.jar$
## Pattern to select jars from the container classloader to be scanned (or null to scan all jars).
# jetty.deploy.webInfScanJarPattern=
## Pattern to exclude discovered ServletContainerInitializers
# jetty.deploy.servletContainerInitializerExclusionPattern=
## Order of discovered ServletContainerInitializers
# jetty.deploy.servletContainerInitializerOrder=

View File

@ -8,7 +8,7 @@
<servlet> <servlet>
<display-name>SerialRestServlet</display-name> <display-name>SerialRestServlet</display-name>
<servlet-name>SerialRestServlet</servlet-name> <servlet-name>SerialRestServlet</servlet-name>
<servlet-class>org.eclipse.jetty.demos.SerialRestServlet</servlet-class> <servlet-class>org.eclipse.jetty.ee9.demosSerialRestServlet</servlet-class>
</servlet> </servlet>
<servlet-mapping> <servlet-mapping>
<servlet-name>SerialRestServlet</servlet-name> <servlet-name>SerialRestServlet</servlet-name>
@ -18,7 +18,7 @@
<servlet> <servlet>
<display-name>AsyncRestServlet</display-name> <display-name>AsyncRestServlet</display-name>
<servlet-name>AsyncRestServlet</servlet-name> <servlet-name>AsyncRestServlet</servlet-name>
<servlet-class>org.eclipse.jetty.demos.AsyncRestServlet</servlet-class> <servlet-class>org.eclipse.jetty.ee9.demosAsyncRestServlet</servlet-class>
<async-supported>true</async-supported> <async-supported>true</async-supported>
</servlet> </servlet>
<servlet-mapping> <servlet-mapping>

View File

@ -14,5 +14,5 @@ webapp
ee9-deploy ee9-deploy
[files] [files]
maven://org.eclipse.jetty.ee9.demos/ee9-demo-async-rest-webapp/${jetty.version}/war|webapps-ee9/ee9-demo-async-rest.war basehome:modules/demo.d/ee9-demo-async-rest.properties|webapps/ee9-demo-async-rest.properties
maven://org.eclipse.jetty.ee9.demos/jetty-ee9-demo-async-rest-webapp/${jetty.version}/war|webapps/ee9-demo-async-rest.war

View File

@ -19,7 +19,7 @@
<New id="context" class="org.eclipse.jetty.ee9.servlet.ServletContextHandler"> <New id="context" class="org.eclipse.jetty.ee9.servlet.ServletContextHandler">
<Set name="contextPath">/hello</Set> <Set name="contextPath">/hello</Set>
<Call name="addServlet"> <Call name="addServlet">
<Arg>org.eclipse.jetty.demos.HelloServlet</Arg> <Arg>org.eclipse.jetty.ee9.demos.HelloServlet</Arg>
<Arg>/</Arg> <Arg>/</Arg>
</Call> </Call>
</New> </New>

View File

@ -19,10 +19,11 @@ ee9-annotations
ext ext
[files] [files]
basehome:modules/demo.d/ee9-demo-jaas.xml|webapps-ee9/ee9-demo-jaas.xml basehome:modules/demo.d/ee9-demo-jaas.xml|webapps/ee9-demo-jaas.xml
basehome:modules/demo.d/ee9-demo-jaas.properties|webapps/ee9-demo-jaas.properties
basehome:modules/demo.d/ee9-demo-login.conf|etc/ee9-demo-login.conf basehome:modules/demo.d/ee9-demo-login.conf|etc/ee9-demo-login.conf
basehome:modules/demo.d/ee9-demo-login.properties|etc/ee9-demo-login.properties basehome:modules/demo.d/ee9-demo-login.properties|etc/ee9-demo-login.properties
maven://org.eclipse.jetty.ee9.demos/ee9-demo-jaas-webapp/${jetty.version}/war|webapps-ee9/ee9-demo-jaas.war maven://org.eclipse.jetty.ee9.demos/jetty-ee9-demo-jaas-webapp/${jetty.version}/war|webapps/ee9-demo-jaas.war
[ini] [ini]
# Enable security via jaas, and configure it # Enable security via jaas, and configure it

View File

@ -24,6 +24,7 @@ ee9-demo-realm
[files] [files]
webapps-ee9/demo-jetty.d/ webapps-ee9/demo-jetty.d/
basehome:modules/demo.d/ee9-demo-jetty.xml|webapps-ee9/ee9-demo-jetty.xml basehome:modules/demo.d/ee9-demo-jetty.xml|webapps/ee9-demo-jetty.xml
basehome:modules/demo.d/ee9-demo-jetty-override-web.xml|webapps-ee9/ee9-demo-jetty.d/ee9-demo-jetty-override-web.xml basehome:modules/demo.d/ee9-demo-jetty-override-web.xml|webapps/ee9-demo-jetty.d/ee9-demo-jetty-override-web.xml
maven://org.eclipse.jetty.ee9.demos/ee9-demo-jetty-webapp/${jetty.version}/war|webapps-ee9/ee9-demo-jetty.war basehome:modules/demo.d/ee9-demo-jetty.properties|webapps/ee9-demo-jetty.properties
maven://org.eclipse.jetty.ee9.demos/jetty-ee9-demo-jetty-webapp/${jetty.version}/war|webapps/ee9-demo-jetty.war

View File

@ -13,5 +13,5 @@ demo
ee9-deploy ee9-deploy
[files] [files]
basehome:modules/demo.d/ee9-demo-moved-context.xml|webapps-ee9/ee9-demo-moved-context.xml basehome:modules/demo.d/ee9-demo-moved-context.xml|webapps/ee9-demo-moved-context.xml

View File

@ -18,6 +18,7 @@ ee9-plus
ee9-demo-mock-resources ee9-demo-mock-resources
[files] [files]
basehome:modules/demo.d/ee9-demo-jndi.xml|webapps-ee9/ee9-demo-jndi.xml basehome:modules/demo.d/ee9-demo-jndi.xml|webapps/ee9-demo-jndi.xml
maven://org.eclipse.jetty.ee9.demos/ee9-demo-jndi-webapp/${jetty.version}/war|webapps-ee9/ee9-demo-jndi.war basehome:modules/demo.d/ee9-demo-jndi.properties|webapps/ee9-demo-jndi.properties
maven://org.eclipse.jetty.ee9.demos/jetty-ee9-demo-jndi-webapp/${jetty.version}/war|webapps/ee9-demo-jndi.war
maven://jakarta.mail/jakarta.mail-api/2.0.0/jar|lib/ext/jakarta.mail-api-2.0.0.jar maven://jakarta.mail/jakarta.mail-api/2.0.0/jar|lib/ext/jakarta.mail-api-2.0.0.jar

View File

@ -14,4 +14,5 @@ jstl
ee9-deploy ee9-deploy
[files] [files]
maven://org.eclipse.jetty.ee9.demos/ee9-demo-jsp-webapp/${jetty.version}/war|webapps-ee9/ee9-demo-jsp.war basehome:modules/demo.d/ee9-demo-jsp.properties|webapps/ee9-demo-jsp.properties
maven://org.eclipse.jetty.ee9.demos/jetty-ee9-demo-jsp-webapp/${jetty.version}/war|webapps/ee9-demo-jsp.war

View File

@ -24,7 +24,7 @@
</goals> </goals>
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>org.eclipse.jetty.demos.ee9-demo-mock-resources</Bundle-SymbolicName> <Bundle-SymbolicName>org.eclipse.jetty.ee9.demos.ee9-demo-mock-resources</Bundle-SymbolicName>
<Bundle-Description>Mock resources used for testing</Bundle-Description> <Bundle-Description>Mock resources used for testing</Bundle-Description>
<Export-Package> <Export-Package>
org.example;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}" org.example;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"

View File

@ -14,4 +14,4 @@ jdbc
ee9-annotations ee9-annotations
[files] [files]
maven://org.eclipse.jetty.ee9.demos/ee9-demo-mock-resources/${jetty.version}/jar|lib/ext/ee9-demo-mock-resources-${jetty.version}.jar maven://org.eclipse.jetty.ee9.demos/jetty-ee9-demo-mock-resources/${jetty.version}/jar|lib/ext/ee9-demo-mock-resources-${jetty.version}.jar

View File

@ -14,4 +14,5 @@ webapp
ee9-deploy ee9-deploy
[files] [files]
maven://org.eclipse.jetty.ee9.demos/ee9-demo-proxy-webapp/${jetty.version}/war|webapps-ee9/ee9-demo-proxy.war basehome:modules/demo.d/ee9-demo-proxy.properties|webapps/ee9-demo-proxy.properties
maven://org.eclipse.jetty.ee9.demos/jetty-ee9-demo-proxy-webapp/${jetty.version}/war|webapps/ee9-demo-proxy.war

View File

@ -12,4 +12,5 @@ webapp
ee9-deploy ee9-deploy
[files] [files]
maven://org.eclipse.jetty.ee9.demos/ee9-demo-simple-webapp/${jetty.version}/war|webapps-ee9/ee9-demo-simple.war basehome:modules/demo.d/ee9-demo-simple.properties|webapps/ee9-demo-simple.properties
maven://org.eclipse.jetty.ee9.demos/jetty-ee9-demo-simple-webapp/${jetty.version}/war|webapps/ee9-demo-simple.war

View File

@ -20,7 +20,7 @@
<extensions>true</extensions> <extensions>true</extensions>
<configuration> <configuration>
<instructions> <instructions>
<Bundle-SymbolicName>org.eclipse.jetty.demos.ee9-demo-servlet-container-initializer;singleton:=true</Bundle-SymbolicName> <Bundle-SymbolicName>org.eclipse.jetty.ee9.demos.ee9-demo-servlet-container-initializer;singleton:=true</Bundle-SymbolicName>
<Bundle-Description>A bundle containing a ServletContainerInitializer for testing</Bundle-Description> <Bundle-Description>A bundle containing a ServletContainerInitializer for testing</Bundle-Description>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability> <Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
<Provide-Capability>osgi.serviceloader; osgi.serviceloader=jakarta.servlet.ServletContainerInitializer</Provide-Capability> <Provide-Capability>osgi.serviceloader; osgi.serviceloader=jakarta.servlet.ServletContainerInitializer</Provide-Capability>

View File

@ -20,5 +20,6 @@ ee9-demo-realm
ee9-demo-mock-resources ee9-demo-mock-resources
[files] [files]
basehome:modules/demo.d/ee9-demo-spec.xml|webapps-ee9/ee9-demo-spec.xml basehome:modules/demo.d/ee9-demo-spec.xml|webapps/ee9-demo-spec.xml
maven://org.eclipse.jetty.ee9.demos/ee9-demo-spec-webapp/${jetty.version}/war|webapps-ee9/ee9-demo-spec.war basehome:modules/demo.d/ee9-demo-spec.properties|webapps/ee9-demo-spec.properties
maven://org.eclipse.jetty.ee9.demos/jetty-ee9-demo-spec-webapp/${jetty.version}/war|webapps/ee9-demo-spec.war

View File

@ -350,7 +350,7 @@ public class JettyHomeForker extends AbstractForker
modulesPath = Files.createDirectories(targetBasePath.resolve("modules")); modulesPath = Files.createDirectories(targetBasePath.resolve("modules"));
etcPath = Files.createDirectories(targetBasePath.resolve("etc")); etcPath = Files.createDirectories(targetBasePath.resolve("etc"));
libPath = Files.createDirectories(targetBasePath.resolve("lib")); libPath = Files.createDirectories(targetBasePath.resolve("lib"));
webappPath = Files.createDirectories(targetBasePath.resolve("webapps-ee9")); webappPath = Files.createDirectories(targetBasePath.resolve("webapps"));
mavenLibPath = Files.createDirectories(libPath.resolve("maven-ee9")); mavenLibPath = Files.createDirectories(libPath.resolve("maven-ee9"));
//copy in the jetty-maven-plugin jar //copy in the jetty-maven-plugin jar

View File

@ -39,7 +39,7 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-io</artifactId> <artifactId>jetty-ee</artifactId>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>

View File

@ -14,6 +14,7 @@
module org.eclipse.jetty.ee9.nested module org.eclipse.jetty.ee9.nested
{ {
requires transitive jetty.servlet.api; requires transitive jetty.servlet.api;
requires transitive org.eclipse.jetty.ee;
requires transitive org.eclipse.jetty.http; requires transitive org.eclipse.jetty.http;
requires transitive org.eclipse.jetty.server; requires transitive org.eclipse.jetty.server;
requires transitive org.eclipse.jetty.session; requires transitive org.eclipse.jetty.session;

View File

@ -198,7 +198,6 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
protected ContextStatus _contextStatus = ContextStatus.NOTSET; protected ContextStatus _contextStatus = ContextStatus.NOTSET;
protected APIContext _apiContext; protected APIContext _apiContext;
private final Map<String, String> _initParams; private final Map<String, String> _initParams;
private boolean _contextPathDefault = true;
private String _defaultRequestCharacterEncoding; private String _defaultRequestCharacterEncoding;
private String _defaultResponseCharacterEncoding; private String _defaultResponseCharacterEncoding;
private String _contextPathEncoded = "/"; private String _contextPathEncoded = "/";
@ -1065,19 +1064,6 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
_coreContextHandler.setClassLoader(classLoader); _coreContextHandler.setClassLoader(classLoader);
} }
/**
* Set the default context path.
* A default context path may be overriden by a default-context-path element
* in a web.xml
*
* @param contextPath The _contextPath to set.
*/
public void setDefaultContextPath(String contextPath)
{
setContextPath(contextPath);
_contextPathDefault = true;
}
public void setDefaultRequestCharacterEncoding(String encoding) public void setDefaultRequestCharacterEncoding(String encoding)
{ {
_defaultRequestCharacterEncoding = encoding; _defaultRequestCharacterEncoding = encoding;
@ -1098,14 +1084,6 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
return _defaultResponseCharacterEncoding; return _defaultResponseCharacterEncoding;
} }
/**
* @return True if the current contextPath is from default settings
*/
public boolean isContextPathDefault()
{
return _contextPathDefault;
}
/** /**
* @param contextPath The _contextPath to set. * @param contextPath The _contextPath to set.
*/ */
@ -1133,7 +1111,6 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
_coreContextHandler.setContextPath(contextPath); _coreContextHandler.setContextPath(contextPath);
_contextPathEncoded = URIUtil.encodePath(contextPath); _contextPathEncoded = URIUtil.encodePath(contextPath);
_contextPathDefault = false;
// update context mappings // update context mappings
if (getServer() != null && getServer().isRunning()) if (getServer() != null && getServer().isRunning())

View File

@ -48,7 +48,7 @@
<Bundle-SymbolicName>${bundle-symbolic-name}</Bundle-SymbolicName> <Bundle-SymbolicName>${bundle-symbolic-name}</Bundle-SymbolicName>
<Bundle-Name>Jetty OSGi Test WebApp Fragment</Bundle-Name> <Bundle-Name>Jetty OSGi Test WebApp Fragment</Bundle-Name>
<Bundle-RequiredExecutionEnvironment>J2SE-1.5</Bundle-RequiredExecutionEnvironment> <Bundle-RequiredExecutionEnvironment>J2SE-1.5</Bundle-RequiredExecutionEnvironment>
<Fragment-Host>org.eclipse.jetty.demos.spec.webapp</Fragment-Host> <Fragment-Host>org.eclipse.jetty.ee9.demos.spec.webapp</Fragment-Host>
<Jetty-WarFragmentResourcePath>/</Jetty-WarFragmentResourcePath> <Jetty-WarFragmentResourcePath>/</Jetty-WarFragmentResourcePath>
</instructions> </instructions>
</configuration> </configuration>

View File

@ -21,41 +21,39 @@
<Call name="addAppProvider"> <Call name="addAppProvider">
<Arg> <Arg>
<New id="WebAppProvider" class="org.eclipse.jetty.deploy.providers.ContextProvider"> <New id="WebAppProvider" class="org.eclipse.jetty.deploy.providers.ContextProvider">
<Set name="defaultEnvironment">ee9</Set> <Set name="EnvironmentName">ee9</Set>
<Set name="monitoredDirName"> <Set name="monitoredDirName">
<Call name="resolvePath" class="org.eclipse.jetty.xml.XmlConfiguration"> <Call name="resolvePath" class="org.eclipse.jetty.xml.XmlConfiguration">
<Arg> <Arg>
<Property name="jetty.base" /> <Property name="jetty.base" />
</Arg> </Arg>
<Arg> <Arg>
<Property name="jetty.deploy.monitoredDir" default="webapps-ee9" /> <Property name="jetty.deploy.monitoredDir" default="webapps" />
</Arg> </Arg>
</Call> </Call>
</Set> </Set>
<Set name="defaultsDescriptor"> <Set name="scanInterval" property="jetty.deploy.scanInterval"/>
<Property> <Set name="defaultsDescriptor" property="jetty.deploy.defaultsDescriptor"/>
<Name>jetty.deploy.defaultsDescriptorPath</Name> <Set name="extractWars" property="jetty.deploy.extractWars" />
<Default> <Set name="parentLoaderPriority" property="jetty.deploy.parentLoaderPriority" />
<Property name="jetty.home" default="." />/etc/webdefault-ee9.xml <Set name="configurationClasses" property="jetty.deploy.configurationClasses" />
</Default> <Set name="tempDir" property="jetty.deploy.tempDir" />
</Property> <Get name="properties">
</Set> <Put name="jetty.deploy.containerScanJarPattern">
<Set name="scanInterval"> <Property name="jetty.deploy.containerScanJarPattern">
<Property name="jetty.deploy.scanInterval" default="1" /> <Default>.*jakarta.servlet.jsp.jstl-.*\.jar$</Default>
</Set> </Property>
<Set name="extractWars"> </Put>
<Property name="jetty.deploy.extractWars" default="true" /> <Put name="jetty.deploy.webInfScanJarPattern">
</Set> <Property name="jetty.deploy.webInfScanJarPattern"/>
<Set name="configurationManager"> </Put>
<New class="org.eclipse.jetty.deploy.PropertiesConfigurationManager"> <Put name="jetty.deploy.servletContainerInitializerExclusionPattern">
<!-- file of context configuration properties <Property name="jetty.deploy.servletContainerInitializerExclusionPattern"/>
<Set name="file"><SystemProperty name="jetty.base"/>/etc/some.properties</Set> </Put>
--> <Put name="jetty.deploy.servletContainerInitializerOrder">
<!-- set a context configuration property <Property name="jetty.deploy.servletContainerInitializerOrder"/>
<Call name="put"><Arg>name</Arg><Arg>value</Arg></Call> </Put>
--> </Get>
</New>
</Set>
</New> </New>
</Arg> </Arg>
</Call> </Call>

View File

@ -11,23 +11,44 @@ ee9-webapp
[lib] [lib]
[files] [files]
webapps-ee9/ webapps/
[xml] [xml]
etc/jetty-ee9-deploy.xml etc/jetty-ee9-deploy.xml
[ini-template] [ini-template]
# Monitored directory name (relative to $jetty.base) ## Monitored directory name (relative to $jetty.base)
# jetty.deploy.monitoredDir=webapps-ee9 # jetty.deploy.monitoredDir=webapps
# - OR - ## - OR -
# Monitored directory path (fully qualified) ## Monitored directory path (fully qualified)
# jetty.deploy.monitoredPath=/var/www/webapps-ee9 # jetty.deploy.monitoredPath=/var/www/webapps
# Defaults Descriptor for all deployed webapps ## Defaults Descriptor for all deployed webapps
# jetty.deploy.defaultsDescriptorPath=${jetty.base}/etc/webdefault-ee9.xml # jetty.deploy.defaultsDescriptor=${jetty.base}/etc/webdefault-ee9.xml
# Monitored directory scan period (seconds) ## Monitored directory scan period (seconds)
# jetty.deploy.scanInterval=1 # jetty.deploy.scanInterval=1
# Whether to extract *.war files ## Whether to extract *.war files
# jetty.deploy.extractWars=true # jetty.deploy.extractWars=true
## Whether to give the parent classloader priority
# jetty.deploy.parentLoaderPriority=true
## Comma separated list of configuration classes to set.
# jetty.deploy.configurationClasses=
## Base temporary directory for deployed web applications.
# jetty.deploy.tempDir=
## Pattern to select jars from the container classloader to be scanned (or null to scan no jars)
# jetty.deploy.containerScanJarPattern=.*jakarta.servlet.jsp.jstl-.*\.jar$
## Pattern to select jars from the container classloader to be scanned (or null to scan all jars).
# jetty.deploy.webInfScanJarPattern=
## Pattern to exclude discovered ServletContainerInitializers
# jetty.deploy.servletContainerInitializerExclusionPattern=
## Order of discovered ServletContainerInitializers
# jetty.deploy.servletContainerInitializerOrder=

View File

@ -36,7 +36,9 @@ import java.util.jar.JarEntry;
import java.util.jar.JarFile; import java.util.jar.JarFile;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.PatternMatcher; import org.eclipse.jetty.util.PatternMatcher;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.resource.EmptyResource; import org.eclipse.jetty.util.resource.EmptyResource;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceCollection; import org.eclipse.jetty.util.resource.ResourceCollection;
@ -186,9 +188,13 @@ public class MetaInfConfiguration extends AbstractConfiguration
*/ */
public void findAndFilterContainerPaths(final WebAppContext context) throws Exception public void findAndFilterContainerPaths(final WebAppContext context) throws Exception
{ {
String pattern = (String)context.getAttribute(CONTAINER_JAR_PATTERN);
if (StringUtil.isBlank(pattern))
return; // TODO review if this short cut will allow later code simplifications
// Apply an initial name filter to the jars to select which will be eventually // Apply an initial name filter to the jars to select which will be eventually
// scanned for META-INF info and annotations. The filter is based on inclusion patterns. // scanned for META-INF info and annotations. The filter is based on inclusion patterns.
ContainerPathNameMatcher containerPathNameMatcher = new ContainerPathNameMatcher(context, (String)context.getAttribute(CONTAINER_JAR_PATTERN)); ContainerPathNameMatcher containerPathNameMatcher = new ContainerPathNameMatcher(context, pattern);
List<URI> containerUris = getAllContainerJars(context); List<URI> containerUris = getAllContainerJars(context);
if (LOG.isDebugEnabled()) if (LOG.isDebugEnabled())
@ -284,22 +290,19 @@ public class MetaInfConfiguration extends AbstractConfiguration
protected List<URI> getAllContainerJars(final WebAppContext context) throws URISyntaxException protected List<URI> getAllContainerJars(final WebAppContext context) throws URISyntaxException
{ {
List<URI> uris = new ArrayList<>(); List<URI> uris = new ArrayList<>();
if (context.getClassLoader() != null) ClassLoader loader = MetaInfConfiguration.class.getClassLoader();
while (loader != null)
{ {
ClassLoader loader = context.getClassLoader().getParent(); if (loader instanceof URLClassLoader)
while (loader != null)
{ {
if (loader instanceof URLClassLoader) URL[] urls = ((URLClassLoader)loader).getURLs();
if (urls != null)
{ {
URL[] urls = ((URLClassLoader)loader).getURLs(); for (URL url : urls)
if (urls != null) uris.add(new URI(url.toString().replaceAll(" ", "%20")));
for (URL url : urls)
{
uris.add(new URI(url.toString().replaceAll(" ", "%20")));
}
} }
loader = loader.getParent();
} }
loader = loader.getParent();
} }
return uris; return uris;
} }

View File

@ -38,10 +38,9 @@ import jakarta.servlet.http.HttpSessionAttributeListener;
import jakarta.servlet.http.HttpSessionBindingListener; import jakarta.servlet.http.HttpSessionBindingListener;
import jakarta.servlet.http.HttpSessionIdListener; import jakarta.servlet.http.HttpSessionIdListener;
import jakarta.servlet.http.HttpSessionListener; import jakarta.servlet.http.HttpSessionListener;
import org.eclipse.jetty.ee9.nested.AbstractHandler; import org.eclipse.jetty.ee.Deployable;
import org.eclipse.jetty.ee9.nested.ContextHandler; import org.eclipse.jetty.ee9.nested.ContextHandler;
import org.eclipse.jetty.ee9.nested.ErrorHandler; import org.eclipse.jetty.ee9.nested.ErrorHandler;
import org.eclipse.jetty.ee9.nested.ManagedAttributeListener;
import org.eclipse.jetty.ee9.nested.SessionHandler; import org.eclipse.jetty.ee9.nested.SessionHandler;
import org.eclipse.jetty.ee9.security.ConstraintAware; import org.eclipse.jetty.ee9.security.ConstraintAware;
import org.eclipse.jetty.ee9.security.ConstraintMapping; import org.eclipse.jetty.ee9.security.ConstraintMapping;
@ -50,13 +49,12 @@ import org.eclipse.jetty.ee9.security.SecurityHandler;
import org.eclipse.jetty.ee9.servlet.ErrorPageErrorHandler; import org.eclipse.jetty.ee9.servlet.ErrorPageErrorHandler;
import org.eclipse.jetty.ee9.servlet.ServletContextHandler; import org.eclipse.jetty.ee9.servlet.ServletContextHandler;
import org.eclipse.jetty.ee9.servlet.ServletHandler; import org.eclipse.jetty.ee9.servlet.ServletHandler;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.Attributes; import org.eclipse.jetty.util.Attributes;
import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.MultiException;
import org.eclipse.jetty.util.TopologicalSort; import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedAttribute;
import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedObject;
@ -79,76 +77,9 @@ import org.slf4j.LoggerFactory;
* the default being {@link WebXmlConfiguration} and * the default being {@link WebXmlConfiguration} and
* {@link JettyWebXmlConfiguration}. * {@link JettyWebXmlConfiguration}.
* *
*
* <p>
* The Start/Configuration of a WebAppContext is rather complex so as to allow
* pluggable behaviour to be added in almost arbitrary ordering. The
* sequence of a WebappContext start is as follows:
* <blockquote>
* {@link #doStart()}:
* <ul>
* <li>{@link #preConfigure()}
* <ul>
* <li>Add all Server class inclusions from all known configurations {@link Configurations#getKnown()}</li>
* <li>{@link #loadConfigurations()}, which uses either explicitly set Configurations or takes the server
* default (which is all known {@link Configuration#isEnabledByDefault()} Configurations.</li>
* <li>Sort the configurations using {@link TopologicalSort} in {@link Configurations#sort()}.</li>
* <li>Add all Server class exclusions from this webapps {@link Configurations}</li>
* <li>Add all System classes inclusions and exclusions for this webapps {@link Configurations}</li>
* <li>Instantiate the WebAppClassLoader (if one not already explicitly set)</li>
* <li>{@link Configuration#preConfigure(WebAppContext)} which calls
* {@link Configuration#preConfigure(WebAppContext)} for this webapps {@link Configurations}</li>
* </ul>
* </li>
* <li>{@link ServletContextHandler#doStart()}
* <ul>
* <li>{@link ContextHandler#doStart()}
* <ul>
* <li>Init {@link MimeTypes}</li>
* <li>enterScope
* <ul>
* <li>{@link #startContext()}
* <ul>
* <li>{@link #configure()}
* <ul>
* <li>Call {@link Configuration#configure(WebAppContext)} on enabled {@link Configurations}</li>
* </ul>
* </li>
* <li>{@link MetaData#resolve(WebAppContext)}</li>
* <li>{@link #startContext()}
* <li>QuickStart may generate here and/or abort start
* <ul>
* <li>{@link ServletContextHandler#startContext}
* <ul>
* <li>Decorate listeners</li>
* <li>{@link ContextHandler#startContext}
* <ul>
* <li>add {@link ManagedAttributeListener}</li>
* <li>{@link AbstractHandler#doStart}</li>
* <li>{@link #callContextInitialized(jakarta.servlet.ServletContextListener, jakarta.servlet.ServletContextEvent)}</li>
* </ul>
* </li>
* <li>{@link ServletHandler#initialize()}</li>
* </ul>
* </li>
* </ul>
* </li>
* </ul>
* </li>
* </ul>
* </li>
* <li>exitScope</li>
* </ul>
* </li>
* </ul>
* </li>
* <li>{@link #postConfigure()}</li>
* </ul>
*
* </blockquote>
*/ */
@ManagedObject("Web Application ContextHandler") @ManagedObject("Web Application ContextHandler")
public class WebAppContext extends ServletContextHandler implements WebAppClassLoader.Context public class WebAppContext extends ServletContextHandler implements WebAppClassLoader.Context, Deployable
{ {
static final Logger LOG = LoggerFactory.getLogger(WebAppContext.class); static final Logger LOG = LoggerFactory.getLogger(WebAppContext.class);
@ -211,6 +142,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
private boolean _throwUnavailableOnStartupException = false; private boolean _throwUnavailableOnStartupException = false;
private MetaData _metadata = new MetaData(); private MetaData _metadata = new MetaData();
private boolean _defaultContextPath = true;
public static WebAppContext getCurrentWebAppContext() public static WebAppContext getCurrentWebAppContext()
{ {
@ -307,6 +239,54 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
parent.addHandler(this); parent.addHandler(this);
} }
@Override
public void initializeDefaults(Map<String, String> properties)
{
for (String property : properties.keySet())
{
String value = properties.get(property);
if (LOG.isDebugEnabled())
LOG.debug("init {}: {}", property, value);
switch (property)
{
case Deployable.WAR -> setWar(value);
case Deployable.BASE_TEMP_DIR -> setAttribute(BASETEMPDIR, value);
case Deployable.CONFIGURATION_CLASSES -> setConfigurationClasses(value == null ? null : value.split(","));
case Deployable.CONTAINER_SCAN_JARS -> setAttribute(MetaInfConfiguration.CONTAINER_JAR_PATTERN, value);
case Deployable.EXTRACT_WARS -> setExtractWAR(Boolean.parseBoolean(value));
case Deployable.PARENT_LOADER_PRIORITY -> setParentLoaderPriority(Boolean.parseBoolean(value));
case Deployable.WEBINF_SCAN_JARS -> setAttribute(MetaInfConfiguration.WEBINF_JAR_PATTERN, value);
case Deployable.DEFAULTS_DESCRIPTOR -> setDefaultsDescriptor(value);
case Deployable.SCI_EXCLUSION_PATTERN -> setAttribute("org.eclipse.jetty.containerInitializerExclusionPattern", value);
case Deployable.SCI_ORDER -> setAttribute("org.eclipse.jetty.containerInitializerOrder", value);
default ->
{
if (LOG.isDebugEnabled() && StringUtil.isNotBlank(value))
LOG.debug("unknown property {}={}", property, value);
}
}
}
_defaultContextPath = true;
}
public boolean isContextPathDefault()
{
return _defaultContextPath;
}
@Override
public void setContextPath(String contextPath)
{
super.setContextPath(contextPath);
_defaultContextPath = false;
}
public void setDefaultContextPath(String contextPath)
{
super.setContextPath(contextPath);
_defaultContextPath = true;
}
/** /**
* @param displayName The servletContextName to set. * @param displayName The servletContextName to set.
*/ */
@ -950,14 +930,14 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
name = String.format("%s@%x", name, hashCode()); name = String.format("%s@%x", name, hashCode());
dumpObjects(out, indent, dumpObjects(out, indent,
Dumpable.named("environment", ENVIRONMENT.getName()), Dumpable.named("environment", ContextHandler.ENVIRONMENT.getName()),
new ClassLoaderDump(getClassLoader()), new ClassLoaderDump(getClassLoader()),
new DumpableCollection("Systemclasses " + name, systemClasses), new DumpableCollection("Systemclasses " + name, systemClasses),
new DumpableCollection("Serverclasses " + name, serverClasses), new DumpableCollection("Serverclasses " + name, serverClasses),
new DumpableCollection("Configurations " + name, _configurations), new DumpableCollection("Configurations " + name, _configurations),
new DumpableCollection("Handler attributes " + name, getAttributes().asAttributeMap().entrySet()), new DumpableCollection("Handler attributes " + name, getAttributes().asAttributeMap().entrySet()),
new DumpableCollection("Context attributes " + name, getServletContext().getContextHandler().asAttributeMap().entrySet()), new DumpableCollection("Context attributes " + name, getServletContext().getContextHandler().asAttributeMap().entrySet()),
new DumpableCollection("Environment attributes " + name, ENVIRONMENT.asAttributeMap().entrySet()), new DumpableCollection("Environment attributes " + name, ContextHandler.ENVIRONMENT.asAttributeMap().entrySet()),
new DumpableCollection("EventListeners " + this, getEventListeners()), new DumpableCollection("EventListeners " + this, getEventListeners()),
new DumpableCollection("Initparams " + name, getInitParams().entrySet()) new DumpableCollection("Initparams " + name, getInitParams().entrySet())
); );

View File

@ -20,7 +20,6 @@ import java.util.List;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.util.resource.Resource;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
@ -131,12 +130,11 @@ public class MetaInfConfigurationTest
* @throws Exception if the test fails * @throws Exception if the test fails
*/ */
@Test @Test
@Disabled // TODO
public void testFindAndFilterContainerPathsJDK9() throws Exception public void testFindAndFilterContainerPathsJDK9() throws Exception
{ {
MetaInfConfiguration config = new MetaInfConfiguration(); MetaInfConfiguration config = new MetaInfConfiguration();
WebAppContext context = new WebAppContext(); WebAppContext context = new WebAppContext();
context.setAttribute(MetaInfConfiguration.CONTAINER_JAR_PATTERN, ".*/jetty-util-[^/]*\\.jar$|.*/jetty-util/target/classes/$|.*/foo-bar-janb.jar"); context.setAttribute(MetaInfConfiguration.CONTAINER_JAR_PATTERN, ".*servlet-api-[^/]*\\.jar$|.*/foo-bar-janb.jar");
WebAppClassLoader loader = new WebAppClassLoader(context); WebAppClassLoader loader = new WebAppClassLoader(context);
context.setClassLoader(loader); context.setClassLoader(loader);
config.findAndFilterContainerPaths(context); config.findAndFilterContainerPaths(context);
@ -145,7 +143,7 @@ public class MetaInfConfigurationTest
for (Resource r : containerResources) for (Resource r : containerResources)
{ {
String s = r.toString(); String s = r.toString();
assertTrue(s.endsWith("foo-bar-janb.jar") || s.contains("jetty-util")); assertTrue(s.endsWith("foo-bar-janb.jar") || s.contains("servlet-api"));
} }
} }
} }

View File

@ -16,7 +16,7 @@ deploy
[files] [files]
webapps-ee10/root-ee10/ webapps-ee10/root-ee10/
webapps-ee10/root-ee10/images/ webapps-ee10/root-ee10/images/
basehome:modules/demo.d/ee10-root/index.html|webapps-ee10/root-ee10/index.html basehome:modules/demo.d/ee10-root/index.html|webapps/root-ee10/index.html
basehome:modules/demo.d/ee10-root/jetty.css|webapps-ee10/root-ee10/jetty.css basehome:modules/demo.d/ee10-root/jetty.css|webapps/root-ee10/jetty.css
basehome:modules/demo.d/ee10-root/images/jetty-pic.png|webapps-ee10/root-ee10/images/jetty-pic.png basehome:modules/demo.d/ee10-root/images/jetty-pic.png|webapps/root-ee10/images/jetty-pic.png
basehome:modules/demo.d/ee10-root/images/webtide_logo.jpg|webapps-ee10/root-ee10/images/webtide_logo.jpg basehome:modules/demo.d/ee10-root/images/webtide_logo.jpg|webapps/root-ee10/images/webtide_logo.jpg

View File

@ -186,7 +186,7 @@
<!-- <module>documentation</module>--> <!-- <module>documentation</module>-->
<module>jetty-core</module> <module>jetty-core</module>
<module>jetty-integrations</module> <module>jetty-integrations</module>
<module>jetty-ee8</module> <!-- <module>jetty-ee8</module>-->
<module>jetty-ee9</module> <module>jetty-ee9</module>
<module>jetty-ee10</module> <module>jetty-ee10</module>
<module>jetty-home</module> <module>jetty-home</module>
@ -1208,6 +1208,11 @@
<artifactId>jetty-deploy</artifactId> <artifactId>jetty-deploy</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-ee</artifactId>
<version>${project.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-hazelcast</artifactId> <artifactId>jetty-hazelcast</artifactId>