Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #11514 - Cleanup jetty.webapp.addServerClasses property behavior for ee10/ee9/ee8 #11516

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ public void handleField(Class<?> clazz, Field field)

//try environment scope next
if (!bound)
bound = NamingEntryUtil.bindToENC(ServletContextHandler.__environment.getName(), name, mappedName);
bound = NamingEntryUtil.bindToENC(ServletContextHandler.ENVIRONMENT.getName(), name, mappedName);

//try Server scope next
if (!bound)
Expand Down Expand Up @@ -313,7 +313,7 @@ public void handleMethod(Class<?> clazz, Method method)

//try the environment's scope
if (!bound)
bound = NamingEntryUtil.bindToENC(ServletContextHandler.__environment.getName(), name, mappedName);
bound = NamingEntryUtil.bindToENC(ServletContextHandler.ENVIRONMENT.getName(), name, mappedName);

//try the server's scope
if (!bound)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@

package org.eclipse.jetty.ee10.plus.webapp;

import java.util.Map;
import java.util.Set;
import javax.naming.Context;
import javax.naming.InitialContext;
Expand Down Expand Up @@ -208,8 +207,8 @@ public void bindEnvEntries(WebAppContext context)
LOG.debug("Binding env entries from the server scope");
doBindings(envCtx, context.getServer());

LOG.debug("Binding env entries from environment {} scope", ServletContextHandler.__environment.getName());
doBindings(envCtx, ServletContextHandler.__environment.getName());
LOG.debug("Binding env entries from environment {} scope", ServletContextHandler.ENVIRONMENT.getName());
doBindings(envCtx, ServletContextHandler.ENVIRONMENT.getName());

LOG.debug("Binding env entries from the context scope");
doBindings(envCtx, context);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,13 @@ public void bindUserTransaction(WebAppContext context)
{
try
{
Transaction.bindTransactionToENC(ServletContextHandler.__environment.getName());
Transaction.bindTransactionToENC(ServletContextHandler.ENVIRONMENT.getName());
}
catch (NameNotFoundException e)
{
try
{
org.eclipse.jetty.plus.jndi.Transaction.bindTransactionToENC(ServletContextHandler.__environment.getName());
org.eclipse.jetty.plus.jndi.Transaction.bindTransactionToENC(ServletContextHandler.ENVIRONMENT.getName());
}
catch (NameNotFoundException x)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,12 @@
public class ServletContextHandler extends ContextHandler
{
private static final Logger LOG = LoggerFactory.getLogger(ServletContextHandler.class);
public static final Environment __environment = Environment.ensure("ee10");
public static final Environment ENVIRONMENT = Environment.ensure("ee10");
/**
* @deprecated Use {@link ServletContextHandler#ENVIRONMENT} instead. will be removed in Jetty 12.1.0.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the part related to when it will be removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree, this is super common in use on open source java projects (spring-boot, spring-framework, dropwizard, tomcat, etc) and benefits developers.
Our own codebase already has many such usages before this PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joakime then we should remove them all.

Spring has a policy (2 minor versions).

We do not know if we ever will have a 12.1.0, maybe we jump to 13 immediately due to the move to Java 21 required by JEE 11.

Or maybe we will have a policy similar to Spring.

Or maybe we retain it for sponsored reasons.

So the comment about 12.1.0 is wrong, in all cases, and must be removed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm on the fence here. I like seeing the deprecated for removal. I also don't mind being given info that will let me know I can keep using it (e.g. knowing it will always be there in 12.0.x). But I also can see that naming a specific future version is not always correct (although we have frequently done it before and survived!).

So perhaps just say it is deprecated for removal "after 12.0.x", and that could be 12.1.0 or 13.0.0

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the comment about 12.1.0 is wrong, in all cases, and must be removed.

I disagree with the "must be removed" part of your reply.
but I'm totally on board with having a minimum 2 minor releases policy.
That would change these references to say "12.2.0" instead, which means even if 13.0.0 gets released, they are removed, as 13.0.0 is after 12.2.0.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joakime then the policy is outlined elsewhere, e.g. in the docs.
Leave the code clean, without comments that are going to rot.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The policy on deprecated doesn't exist in any documentation in Jetty.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, let's add it, then. But it is orthogonal to this issue.

*/
@Deprecated(since = "12.0.8", forRemoval = true)
public static final Environment __environment = ENVIRONMENT;
Comment on lines +133 to +138
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just standardizing the public constant to the same way we have it in ee9/ee8.

public static final Class<?>[] SERVLET_LISTENER_TYPES =
{
ServletContextListener.class,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Call class="org.eclipse.jetty.ee10.webapp.WebAppContext" name="addSystemClasses">
<Arg><Ref refid="Server"/></Arg>
gregw marked this conversation as resolved.
Show resolved Hide resolved
<Arg>
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
<Arg><Property name="jetty.webapp.addSystemClasses"/></Arg>
Expand All @@ -12,7 +11,6 @@
</Call>

<Call class="org.eclipse.jetty.ee10.webapp.WebAppContext" name="addServerClasses">
<Arg><Ref refid="Server"/></Arg>
<Arg>
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
<Arg><Property name="jetty.webapp.addServerClasses"/></Arg>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -486,7 +486,7 @@ public void postConfigure() throws Exception
protected void doStart() throws Exception
{
ClassLoader old = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(__environment.getClassLoader());
Thread.currentThread().setContextClassLoader(ServletContextHandler.ENVIRONMENT.getClassLoader());
try
{
_metadata.setAllowDuplicateFragmentNames(isAllowDuplicateFragmentNames());
Expand Down Expand Up @@ -728,20 +728,20 @@ public void setServer(Server server)
{
if (__dftSystemClasses.equals(_systemClasses))
{
Object systemClasses = server.getAttribute(SERVER_SYS_CLASSES);
if (systemClasses instanceof String[])
systemClasses = new ClassMatcher((String[])systemClasses);
if (systemClasses instanceof ClassMatcher)
_systemClasses.add(((ClassMatcher)systemClasses).getPatterns());
Object systemClasses = ServletContextHandler.ENVIRONMENT.getAttribute(SERVER_SYS_CLASSES);
if (systemClasses instanceof String[] patterns)
_systemClasses.add(patterns);
if (systemClasses instanceof ClassMatcher classMatcher)
_systemClasses.add(classMatcher.getPatterns());
}

if (__dftServerClasses.equals(_serverClasses))
{
Object serverClasses = server.getAttribute(SERVER_SRV_CLASSES);
if (serverClasses instanceof String[])
serverClasses = new ClassMatcher((String[])serverClasses);
if (serverClasses instanceof ClassMatcher)
_serverClasses.add(((ClassMatcher)serverClasses).getPatterns());
Object serverClasses = ServletContextHandler.ENVIRONMENT.getAttribute(SERVER_SRV_CLASSES);
if (serverClasses instanceof String[] patterns)
_serverClasses.add(patterns);
if (serverClasses instanceof ClassMatcher classMatcher)
_serverClasses.add(classMatcher.getPatterns());
}
}
}
Expand Down Expand Up @@ -1383,24 +1383,62 @@ public MetaData getMetaData()
return _metadata;
}

public static void addServerClasses(Server server, String... pattern)
/**
* @param server ignored.
* @param patterns the patterns to add
* @deprecated use {@link #addServerClasses(String...)} instead, will be removed in Jetty 12.1.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove when it will be removed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method that doesn't take a server does a different job. That sets the default for all servers rather than this method, which sets the default for a specific server.

What is the replacement for setting the default for a specific server? That should be linked here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's at the heart of what caused the issue.

The Attributes reference passed to addServerClasses was not used by the WebAppContext.setServer(Server server) call that needs the configuration.

Now with this PR the add(Server|System)Classes and setServer(Server) both use the environment specific Attributes locations.
Which works great, and even allows for wacky setups where 1 environment has a different setup than a different environment.

Do we have something like a jetty-core level WebAppContext (or something) that can be used as the Server level one?
I'm on the fence with the idea of having a Server.add(Server|System)Classes method which only has a List<String> (not the ClassMatcher option), but it feels like the wrong place for it.
Interestingly, while working this, I found a bug in the ee8 layer's XML where it attempted to use the Server instance to call WebAppContext.addServerClasses(Server, String...), but due to XML order that Server didn't exist yet, which was simply worked around by using the Environment Attributes instead.

How about in a followup PR I move the 2 ClassMatcher impls (from ee10 & ee9) to jetty-util, and then put the Attributes neutral version in the new jetty-util code?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@joakime note that the server classes are set on a static constant ServletContextHandler.ENVIRONMENT, so if you have 2 Servers in the same JVM, and you want different serverClasses configuration, you cannot.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ServletContextHandler.ENVIRONMENT (that exists in ee10, ee9, ee8) are JVM statics ATM (in HEAD).
I think changing that is out of scope for this PR, but I can see that possibly being a useful concept in the long run.

*/
@Deprecated(since = "12.0.8", forRemoval = true)
public static void addServerClasses(Server server, String... patterns)
{
addServerClasses(patterns);
}

/**
* Add a Server Class pattern to use for all ee10 WebAppContexts.
* @param patterns the patterns to use
* @see #getServerClassMatcher()
* @see #getServerClasses()
*/
public static void addServerClasses(String... patterns)
{
if (LOG.isDebugEnabled())
LOG.debug("Adding {} ServerClasses: {}", ServletContextHandler.ENVIRONMENT, String.join(", ", patterns));
addClasses(__dftServerClasses, SERVER_SRV_CLASSES, patterns);
}

/**
* @param server ignored.
* @param patterns the patterns to add
* @deprecated use {@link #addSystemClasses(String...)} instead, will be removed in Jetty 12.1.0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove when it will be removed.

*/
@Deprecated(since = "12.0.8", forRemoval = true)
public static void addSystemClasses(Server server, String... patterns)
{
addClasses(__dftServerClasses, SERVER_SRV_CLASSES, server, pattern);
addSystemClasses(patterns);
}

public static void addSystemClasses(Server server, String... pattern)
/**
* Add a System Class pattern to use for all ee10 WebAppContexts.
* @param patterns the patterns to use
* @see #getSystemClassMatcher()
* @see #getSystemClasses()
*/
public static void addSystemClasses(String... patterns)
{
addClasses(__dftSystemClasses, SERVER_SYS_CLASSES, server, pattern);
if (LOG.isDebugEnabled())
LOG.debug("Adding {} SystemClasses: {}", ServletContextHandler.ENVIRONMENT, String.join(", ", patterns));
addClasses(__dftSystemClasses, SERVER_SYS_CLASSES, patterns);
}

private static void addClasses(ClassMatcher matcher, String attribute, Server server, String... pattern)
private static void addClasses(ClassMatcher matcher, String attributeKey, String... pattern)
{
if (pattern == null || pattern.length == 0)
return;

// look for a Server attribute with the list of System classes
// to apply to every web application. If not present, use our defaults.
Object o = server.getAttribute(attribute);
// look for a ClassMatcher attribute with the list of Server / System classes
// to apply to every ee10 web application. If not present, use our defaults.
Object o = ServletContextHandler.ENVIRONMENT.getAttribute(attributeKey);
if (o instanceof ClassMatcher)
{
((ClassMatcher)o).add(pattern);
Expand All @@ -1415,6 +1453,6 @@ private static void addClasses(ClassMatcher matcher, String attribute, Server se
int l = classes.length;
classes = Arrays.copyOf(classes, l + pattern.length);
System.arraycopy(pattern, 0, classes, l, pattern.length);
server.setAttribute(attribute, classes);
ServletContextHandler.ENVIRONMENT.setAttribute(attributeKey, classes);
gregw marked this conversation as resolved.
Show resolved Hide resolved
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ private static class WebDescriptorParser extends XmlParser
public WebDescriptorParser(boolean validating) throws IOException
{
super(validating);
String catalogName = "catalog-%s.xml".formatted(ServletContextHandler.__environment.getName());
String catalogName = "catalog-%s.xml".formatted(ServletContextHandler.ENVIRONMENT.getName());
URL url = WebDescriptor.class.getResource(catalogName);
if (url == null)
throw new IllegalStateException("Catalog not found: %s/%s".formatted(WebDescriptor.class.getPackageName(), catalogName));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.toolchain.test.FS;
import org.eclipse.jetty.toolchain.test.MavenPaths;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
Expand Down Expand Up @@ -72,6 +73,7 @@
import static org.hamcrest.Matchers.either;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
Expand Down Expand Up @@ -802,4 +804,52 @@ public void testSetServerPropagation()

assertThat(handler.getServer(), sameInstance(server));
}

@Test
public void testAddServerClasses() throws Exception
{
Server server = newServer();

String testPattern = "org.eclipse.jetty.ee10.webapp.test.";

WebAppContext.addServerClasses(testPattern);

WebAppContext context = new WebAppContext();
context.setContextPath("/");
Path warPath = MavenPaths.findTestResourceFile("wars/dump.war");
context.setBaseResource(context.getResourceFactory().newResource(warPath));

server.setHandler(context);
server.start();

List<String> serverClasses = List.of(context.getServerClasses());
assertThat("Should have environment specific test pattern", serverClasses, hasItem(testPattern));
assertThat("Should have pattern from JaasConfiguration", serverClasses, hasItem("-org.eclipse.jetty.security.jaas."));
for (String defaultServerClass: WebAppContext.__dftServerClasses)
assertThat("Should have default patterns", serverClasses, hasItem(defaultServerClass));
}

@Test
public void testAddSystemClasses() throws Exception
{
Server server = newServer();

String testPattern = "org.eclipse.jetty.ee10.webapp.test.";

WebAppContext.addSystemClasses(testPattern);

WebAppContext context = new WebAppContext();
context.setContextPath("/");
Path warPath = MavenPaths.findTestResourceFile("wars/dump.war");
context.setBaseResource(context.getResourceFactory().newResource(warPath));

server.setHandler(context);
server.start();

List<String> systemClasses = List.of(context.getSystemClasses());
assertThat("Should have environment specific test pattern", systemClasses, hasItem(testPattern));
assertThat("Should have pattern from JaasConfiguration", systemClasses, hasItem("org.eclipse.jetty.security.jaas."));
for (String defaultSystemClass: WebAppContext.__dftSystemClasses)
assertThat("Should have default patterns", systemClasses, hasItem(defaultSystemClass));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Call class="org.eclipse.jetty.ee8.webapp.WebAppContext" name="addSystemClasses">
<Arg><Ref refid="Environment"/></Arg>
<Arg>
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
<Arg><Property name="jetty.webapp.addSystemClasses"/></Arg>
Expand All @@ -12,7 +11,6 @@
</Call>

<Call class="org.eclipse.jetty.ee8.webapp.WebAppContext" name="addServerClasses">
<Arg><Ref refid="Environment"/></Arg>
<Arg>
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
<Arg><Property name="jetty.webapp.addServerClasses"/></Arg>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Call class="org.eclipse.jetty.ee9.webapp.WebAppContext" name="addSystemClasses">
<Arg><Ref refid="Environment"/></Arg>
<Arg>
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
<Arg><Property name="jetty.webapp.addSystemClasses"/></Arg>
Expand All @@ -12,7 +11,6 @@
</Call>

<Call class="org.eclipse.jetty.ee9.webapp.WebAppContext" name="addServerClasses">
<Arg><Ref refid="Environment"/></Arg>
<Arg>
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
<Arg><Property name="jetty.webapp.addServerClasses"/></Arg>
Expand Down
Loading
Loading