Move ClassMatcher to core to have a consistent fix for addServerClasses in all environments (#11566)
* Issue #11514 - Cleanup `jetty.webapp.addServerClasses` property behavior for ee10/ee9/ee8 * Fix test * Merging patterns (default -> env -> config) * Moved ClassMatcher to util * Adding more deprecations * Changing XML demos/tests to use new getter names * rollback xml changes in ee9/ee8 --------- Co-authored-by: Joakim Erdfelt <joakim.erdfelt@gmail.com> Co-authored-by: Jan Bartel <janb@webtide.com>
This commit is contained in:
parent
83526f77d3
commit
30bee710f1
|
@ -128,7 +128,7 @@ Appends the value to the existing value.
|
||||||
This is useful to append a value to properties that accept a comma separated list of values, for example:
|
This is useful to append a value to properties that accept a comma separated list of values, for example:
|
||||||
+
|
+
|
||||||
----
|
----
|
||||||
jetty.webapp.addServerClasses+=,com.acme
|
jetty.webapp.addProtectedClasses+=,com.acme
|
||||||
----
|
----
|
||||||
+
|
+
|
||||||
// TODO: check what happens if the property is empty and +=,value is done: is the comma stripped? If so add a sentence about this.
|
// TODO: check what happens if the property is empty and +=,value is done: is the comma stripped? If so add a sentence about this.
|
||||||
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
<?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">
|
||||||
|
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-core</artifactId>
|
||||||
|
<version>12.0.9-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>jetty-ee</artifactId>
|
||||||
|
<name>Core :: EE Common</name>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<bundle-symbolic-name>${project.groupId}.ee</bundle-symbolic-name>
|
||||||
|
<spotbugs.onlyAnalyze>org.eclipse.jetty.ee.*</spotbugs.onlyAnalyze>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-server</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.slf4j</groupId>
|
||||||
|
<artifactId>slf4j-api</artifactId>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-slf4j-impl</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty.tests</groupId>
|
||||||
|
<artifactId>jetty-test-multipart</artifactId>
|
||||||
|
<version>${project.version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||||
|
<artifactId>jetty-test-helper</artifactId>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.felix</groupId>
|
||||||
|
<artifactId>maven-bundle-plugin</artifactId>
|
||||||
|
<extensions>true</extensions>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<argLine>@{argLine} ${jetty.surefire.argLine} --add-reads org.eclipse.jetty.ee=org.eclipse.jetty.logging</argLine>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
</project>
|
|
@ -0,0 +1,23 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||||
|
|
||||||
|
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||||
|
<Call class="org.eclipse.jetty.ee.WebAppClassLoading" name="addProtectedClasses">
|
||||||
|
<Arg><Ref refid="Server"/></Arg>
|
||||||
|
<Arg>
|
||||||
|
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
|
||||||
|
<Arg><Property name="jetty.server.addProtectedClasses"/></Arg>
|
||||||
|
</Call>
|
||||||
|
</Arg>
|
||||||
|
</Call>
|
||||||
|
|
||||||
|
<Call class="org.eclipse.jetty.ee.WebAppClassLoading" name="addHiddenClasses">
|
||||||
|
<Arg><Ref refid="Server"/></Arg>
|
||||||
|
<Arg>
|
||||||
|
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
|
||||||
|
<Arg><Property name="jetty.server.addHiddenClasses"/></Arg>
|
||||||
|
</Call>
|
||||||
|
</Arg>
|
||||||
|
</Call>
|
||||||
|
|
||||||
|
</Configure>
|
|
@ -0,0 +1,31 @@
|
||||||
|
# DO NOT EDIT THIS FILE - See: https://eclipse.dev/jetty/documentation/
|
||||||
|
|
||||||
|
[description]
|
||||||
|
# tag::description[]
|
||||||
|
This module provide common configuration of Java Servlet web applications over all environments.
|
||||||
|
# end::description[]
|
||||||
|
|
||||||
|
[xml]
|
||||||
|
etc/jetty-ee-webapp.xml
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
lib/jetty-ee-${jetty.version}.jar
|
||||||
|
|
||||||
|
[ini-template]
|
||||||
|
# tag::ini-template[]
|
||||||
|
## Add to the server wide default jars and packages protected or hidden from webapps.
|
||||||
|
## Protected (aka System) classes cannot be overridden by a webapp.
|
||||||
|
## Hidden (aka Server) classes cannot be seen by a webapp
|
||||||
|
## Lists of patterns are comma separated and may be either:
|
||||||
|
## + a qualified classname e.g. 'com.acme.Foo'
|
||||||
|
## + a package name e.g. 'net.example.'
|
||||||
|
## + a jar file e.g. '${jetty.base.uri}/lib/dependency.jar'
|
||||||
|
## + a directory of jars,resource or classes e.g. '${jetty.base.uri}/resources'
|
||||||
|
## + A pattern preceded with a '-' is an exclusion, all other patterns are inclusions
|
||||||
|
##
|
||||||
|
## The +=, operator appends to a CSV list with a comma as needed.
|
||||||
|
##
|
||||||
|
#jetty.server.addProtectedClasses+=,org.example.
|
||||||
|
#jetty.server.addHiddenClasses+=,org.example.
|
||||||
|
# end::ini-template[]
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995 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
|
||||||
|
// ========================================================================
|
||||||
|
//
|
||||||
|
|
||||||
|
module org.eclipse.jetty.ee
|
||||||
|
{
|
||||||
|
requires org.slf4j;
|
||||||
|
|
||||||
|
requires transitive org.eclipse.jetty.util;
|
||||||
|
requires transitive org.eclipse.jetty.server;
|
||||||
|
|
||||||
|
exports org.eclipse.jetty.ee;
|
||||||
|
}
|
|
@ -0,0 +1,214 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995 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 org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.util.Attributes;
|
||||||
|
import org.eclipse.jetty.util.ClassMatcher;
|
||||||
|
import org.eclipse.jetty.util.component.Environment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common attributes and methods for configuring the {@link ClassLoader Class loading} of web application:
|
||||||
|
* <ul>
|
||||||
|
* <li>Protected (a.k.a. System) classes are classes typically provided by the JVM, that cannot be replaced by the
|
||||||
|
* web application, and they are always loaded via the environment or system classloader. They are visible but
|
||||||
|
* protected.</li>
|
||||||
|
* <li>Hidden (a.k.a. Server) classes are those used to implement the Server and are not made available to the
|
||||||
|
* web application. They are hidden from the web application {@link ClassLoader}.</li>
|
||||||
|
* </ul>
|
||||||
|
* <p>These protections are set to reasonable defaults {@link #DEFAULT_PROTECTED_CLASSES} and {@link #DEFAULT_HIDDEN_CLASSES},
|
||||||
|
* which may be programmatically configured and will affect the defaults applied to all web applications in the same JVM.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The defaults applied by a specific {@link Server} can be configured using {@link #addProtectedClasses(Server, String...)} and
|
||||||
|
* {@link #addHiddenClasses(Server, String...)}. Alternately the {@link Server} attributes {@link #PROTECTED_CLASSES_ATTRIBUTE}
|
||||||
|
* and {@link #HIDDEN_CLASSES_ATTRIBUTE} may be used to direct set a {@link ClassMatcher} to use for all web applications
|
||||||
|
* within the server instance.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* The defaults applied by a specific {@link Environment} can be configured using {@link #addProtectedClasses(Environment, String...)} and
|
||||||
|
* {@link #addHiddenClasses(Environment, String...)}. Alternately the {@link Environment} attributes {@link #PROTECTED_CLASSES_ATTRIBUTE}
|
||||||
|
* and {@link #HIDDEN_CLASSES_ATTRIBUTE} may be used to direct set a {@link ClassMatcher} to use for all web applications
|
||||||
|
* within the server instance.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Ultimately, the configurations set by this class only affects the defaults applied to each web application
|
||||||
|
* {@link org.eclipse.jetty.server.handler.ContextHandler Context} and the {@link ClassMatcher} fields of the web applications
|
||||||
|
* can be directly access to configure a specific context.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class WebAppClassLoading
|
||||||
|
{
|
||||||
|
public static final String PROTECTED_CLASSES_ATTRIBUTE = "org.eclipse.jetty.webapp.systemClasses";
|
||||||
|
public static final String HIDDEN_CLASSES_ATTRIBUTE = "org.eclipse.jetty.webapp.serverClasses";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default protected (system) classes used by a web application, which will be applied to the {@link ClassMatcher}s created
|
||||||
|
* by {@link #getProtectedClasses(Environment)}.
|
||||||
|
*/
|
||||||
|
public static final ClassMatcher DEFAULT_PROTECTED_CLASSES = new ClassMatcher(
|
||||||
|
"java.", // Java SE classes (per servlet spec v2.5 / SRV.9.7.2)
|
||||||
|
"javax.", // Java SE classes (per servlet spec v2.5 / SRV.9.7.2)
|
||||||
|
"jakarta.", // Jakarta classes (per servlet spec v5.0 / Section 15.2.1)
|
||||||
|
"org.xml.", // javax.xml
|
||||||
|
"org.w3c." // javax.xml
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default hidden (server) classes used by a web application, which can be applied to the {@link ClassMatcher}s created
|
||||||
|
* by {@link #getHiddenClasses(Environment)}.
|
||||||
|
*/
|
||||||
|
public static final ClassMatcher DEFAULT_HIDDEN_CLASSES = new ClassMatcher(
|
||||||
|
"org.eclipse.jetty." // hide jetty classes
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default protected (system) classes for a {@link Server}
|
||||||
|
* @param server The {@link Server} for the defaults
|
||||||
|
* @return The default protected (system) classes for the {@link Server}, which will be empty if not previously configured.
|
||||||
|
*/
|
||||||
|
public static ClassMatcher getProtectedClasses(Server server)
|
||||||
|
{
|
||||||
|
return getClassMatcher(server, PROTECTED_CLASSES_ATTRIBUTE, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default protected (system) classes for an {@link Environment}
|
||||||
|
* @param environment The {@link Server} for the defaults
|
||||||
|
* @return The default protected (system) classes for the {@link Environment}, which will be the {@link #DEFAULT_PROTECTED_CLASSES} if not previously configured.
|
||||||
|
*/
|
||||||
|
public static ClassMatcher getProtectedClasses(Environment environment)
|
||||||
|
{
|
||||||
|
return getClassMatcher(environment, PROTECTED_CLASSES_ATTRIBUTE, DEFAULT_PROTECTED_CLASSES);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a protected (system) Class pattern to use for all WebAppContexts.
|
||||||
|
* @param patterns the patterns to use
|
||||||
|
*/
|
||||||
|
public static void addProtectedClasses(String... patterns)
|
||||||
|
{
|
||||||
|
DEFAULT_PROTECTED_CLASSES.add(patterns);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a protected (system) Class pattern to use for all WebAppContexts of a given {@link Server}.
|
||||||
|
* @param attributes The {@link Attributes} instance to add classes to
|
||||||
|
* @param patterns the patterns to use
|
||||||
|
*/
|
||||||
|
public static void addProtectedClasses(Attributes attributes, String... patterns)
|
||||||
|
{
|
||||||
|
if (patterns != null && patterns.length > 0)
|
||||||
|
getClassMatcher(attributes, PROTECTED_CLASSES_ATTRIBUTE, null).add(patterns);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a protected (system) Class pattern to use for all WebAppContexts of a given {@link Server}.
|
||||||
|
* @param server The {@link Server} instance to add classes to
|
||||||
|
* @param patterns the patterns to use
|
||||||
|
*/
|
||||||
|
public static void addProtectedClasses(Server server, String... patterns)
|
||||||
|
{
|
||||||
|
if (patterns != null && patterns.length > 0)
|
||||||
|
getClassMatcher(server, PROTECTED_CLASSES_ATTRIBUTE, null).add(patterns);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a protected (system) Class pattern to use for WebAppContexts of a given environment.
|
||||||
|
* @param environment The {@link Environment} instance to add classes to
|
||||||
|
* @param patterns the patterns to use
|
||||||
|
*/
|
||||||
|
public static void addProtectedClasses(Environment environment, String... patterns)
|
||||||
|
{
|
||||||
|
if (patterns != null && patterns.length > 0)
|
||||||
|
getClassMatcher(environment, PROTECTED_CLASSES_ATTRIBUTE, DEFAULT_PROTECTED_CLASSES).add(patterns);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default hidden (server) classes for a {@link Server}
|
||||||
|
* @param server The {@link Server} for the defaults
|
||||||
|
* @return The default hidden (server) classes for the {@link Server}, which will be empty if not previously configured.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static ClassMatcher getHiddenClasses(Server server)
|
||||||
|
{
|
||||||
|
return getClassMatcher(server, HIDDEN_CLASSES_ATTRIBUTE, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the default hidden (server) classes for an {@link Environment}
|
||||||
|
* @param environment The {@link Server} for the defaults
|
||||||
|
* @return The default hidden (server) classes for the {@link Environment}, which will be {@link #DEFAULT_PROTECTED_CLASSES} if not previously configured.
|
||||||
|
*/
|
||||||
|
public static ClassMatcher getHiddenClasses(Environment environment)
|
||||||
|
{
|
||||||
|
return getClassMatcher(environment, HIDDEN_CLASSES_ATTRIBUTE, DEFAULT_HIDDEN_CLASSES);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a hidden (server) Class pattern to use for all WebAppContexts of a given {@link Server}.
|
||||||
|
* @param patterns the patterns to use
|
||||||
|
*/
|
||||||
|
public static void addHiddenClasses(String... patterns)
|
||||||
|
{
|
||||||
|
DEFAULT_HIDDEN_CLASSES.add(patterns);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a hidden (server) Class pattern to use for all WebAppContexts of a given {@link Server}.
|
||||||
|
* @param attributes The {@link Attributes} instance to add classes to
|
||||||
|
* @param patterns the patterns to use
|
||||||
|
*/
|
||||||
|
@Deprecated (forRemoval = true)
|
||||||
|
public static void addHiddenClasses(Attributes attributes, String... patterns)
|
||||||
|
{
|
||||||
|
if (patterns != null && patterns.length > 0)
|
||||||
|
getClassMatcher(attributes, HIDDEN_CLASSES_ATTRIBUTE, null).add(patterns);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a hidden (server) Class pattern to use for all WebAppContexts of a given {@link Server}.
|
||||||
|
* @param server The {@link Server} instance to add classes to
|
||||||
|
* @param patterns the patterns to use
|
||||||
|
*/
|
||||||
|
public static void addHiddenClasses(Server server, String... patterns)
|
||||||
|
{
|
||||||
|
if (patterns != null && patterns.length > 0)
|
||||||
|
getClassMatcher(server, HIDDEN_CLASSES_ATTRIBUTE, null).add(patterns);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a hidden (server) Class pattern to use for all ee9 WebAppContexts.
|
||||||
|
* @param environment The {@link Environment} instance to add classes to
|
||||||
|
* @param patterns the patterns to use
|
||||||
|
*/
|
||||||
|
public static void addHiddenClasses(Environment environment, String... patterns)
|
||||||
|
{
|
||||||
|
if (patterns != null && patterns.length > 0)
|
||||||
|
getClassMatcher(environment, HIDDEN_CLASSES_ATTRIBUTE, DEFAULT_HIDDEN_CLASSES).add(patterns);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ClassMatcher getClassMatcher(Attributes attributes, String attribute, ClassMatcher defaultPatterns)
|
||||||
|
{
|
||||||
|
Object existing = attributes.getAttribute(attribute);
|
||||||
|
if (existing instanceof ClassMatcher cm)
|
||||||
|
return cm;
|
||||||
|
|
||||||
|
ClassMatcher classMatcher = (existing instanceof String[] stringArray)
|
||||||
|
? new ClassMatcher(stringArray) : new ClassMatcher(defaultPatterns);
|
||||||
|
attributes.setAttribute(attribute, classMatcher);
|
||||||
|
return classMatcher;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,222 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995 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 orge.eclipse.jetty.ee;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.ee.WebAppClassLoading;
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.util.ClassMatcher;
|
||||||
|
import org.eclipse.jetty.util.component.Environment;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.contains;
|
||||||
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.hamcrest.Matchers.hasItemInArray;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.hamcrest.Matchers.sameInstance;
|
||||||
|
|
||||||
|
public class WebAppClassLoadingTest
|
||||||
|
{
|
||||||
|
@BeforeEach
|
||||||
|
public void beforeEach()
|
||||||
|
{
|
||||||
|
Environment.ensure("Test");
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void afterEach()
|
||||||
|
{
|
||||||
|
Environment.ensure("Test").clearAttributes();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testServerDefaults()
|
||||||
|
{
|
||||||
|
Server server = new Server();
|
||||||
|
ClassMatcher protect = WebAppClassLoading.getProtectedClasses(server);
|
||||||
|
assertThat(protect.size(), is(0));
|
||||||
|
assertThat(server.getAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE), sameInstance(protect));
|
||||||
|
ClassMatcher hide = WebAppClassLoading.getHiddenClasses(server);
|
||||||
|
assertThat(hide.size(), is(0));
|
||||||
|
assertThat(server.getAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE), sameInstance(hide));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testServerAttributeDefaults()
|
||||||
|
{
|
||||||
|
Server server = new Server();
|
||||||
|
ClassMatcher protect = new ClassMatcher("org.protect.");
|
||||||
|
server.setAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE, protect);
|
||||||
|
ClassMatcher hide = new ClassMatcher("org.hide.");
|
||||||
|
server.setAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE, hide);
|
||||||
|
|
||||||
|
assertThat(WebAppClassLoading.getProtectedClasses(server), sameInstance(protect));
|
||||||
|
assertThat(WebAppClassLoading.getHiddenClasses(server), sameInstance(hide));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testServerStringAttributeDefaults()
|
||||||
|
{
|
||||||
|
Server server = new Server();
|
||||||
|
server.setAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE, new String[] {"org.protect."});
|
||||||
|
server.setAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE, new String[] {"org.hide."});
|
||||||
|
|
||||||
|
ClassMatcher protect = WebAppClassLoading.getProtectedClasses(server);
|
||||||
|
assertThat(protect.size(), is(1));
|
||||||
|
assertThat(Arrays.asList(protect.getPatterns()), contains("org.protect."));
|
||||||
|
assertThat(server.getAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE), sameInstance(protect));
|
||||||
|
ClassMatcher hide = WebAppClassLoading.getHiddenClasses(server);
|
||||||
|
assertThat(hide.size(), is(1));
|
||||||
|
assertThat(Arrays.asList(hide.getPatterns()), contains("org.hide."));
|
||||||
|
assertThat(server.getAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE), sameInstance(hide));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testServerProgrammaticDefaults()
|
||||||
|
{
|
||||||
|
Server server = new Server();
|
||||||
|
WebAppClassLoading.addProtectedClasses(server, "org.protect.");
|
||||||
|
WebAppClassLoading.addHiddenClasses(server, "org.hide.");
|
||||||
|
|
||||||
|
ClassMatcher protect = WebAppClassLoading.getProtectedClasses(server);
|
||||||
|
assertThat(protect.size(), is(1));
|
||||||
|
assertThat(Arrays.asList(protect.getPatterns()), contains("org.protect."));
|
||||||
|
assertThat(server.getAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE), sameInstance(protect));
|
||||||
|
ClassMatcher hide = WebAppClassLoading.getHiddenClasses(server);
|
||||||
|
assertThat(hide.size(), is(1));
|
||||||
|
assertThat(Arrays.asList(hide.getPatterns()), contains("org.hide."));
|
||||||
|
assertThat(server.getAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE), sameInstance(hide));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testServerAddPatterns()
|
||||||
|
{
|
||||||
|
Server server = new Server();
|
||||||
|
ClassMatcher protect = WebAppClassLoading.getProtectedClasses(server);
|
||||||
|
ClassMatcher hide = WebAppClassLoading.getHiddenClasses(server);
|
||||||
|
|
||||||
|
assertThat(protect.size(), is(0));
|
||||||
|
assertThat(hide.size(), is(0));
|
||||||
|
|
||||||
|
WebAppClassLoading.addProtectedClasses(server, "org.protect.", "com.protect.");
|
||||||
|
WebAppClassLoading.addHiddenClasses(server, "org.hide.", "com.hide.");
|
||||||
|
|
||||||
|
assertThat(protect.size(), is(2));
|
||||||
|
assertThat(Arrays.asList(protect.getPatterns()), containsInAnyOrder("org.protect.", "com.protect."));
|
||||||
|
assertThat(server.getAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE), sameInstance(protect));
|
||||||
|
|
||||||
|
assertThat(hide.size(), is(2));
|
||||||
|
assertThat(Arrays.asList(hide.getPatterns()), containsInAnyOrder("org.hide.", "com.hide."));
|
||||||
|
assertThat(server.getAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE), sameInstance(hide));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnvironmentDefaults()
|
||||||
|
{
|
||||||
|
Environment environment = Environment.get("Test");
|
||||||
|
ClassMatcher protect = WebAppClassLoading.getProtectedClasses(environment);
|
||||||
|
assertThat(protect, equalTo(WebAppClassLoading.DEFAULT_PROTECTED_CLASSES));
|
||||||
|
assertThat(environment.getAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE), sameInstance(protect));
|
||||||
|
ClassMatcher hide = WebAppClassLoading.getHiddenClasses(environment);
|
||||||
|
assertThat(hide, equalTo(WebAppClassLoading.DEFAULT_HIDDEN_CLASSES));
|
||||||
|
assertThat(environment.getAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE), sameInstance(hide));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnvironmentAttributeDefaults()
|
||||||
|
{
|
||||||
|
Environment environment = Environment.get("Test");
|
||||||
|
ClassMatcher protect = new ClassMatcher("org.protect.");
|
||||||
|
environment.setAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE, protect);
|
||||||
|
ClassMatcher hide = new ClassMatcher("org.hide.");
|
||||||
|
environment.setAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE, hide);
|
||||||
|
|
||||||
|
assertThat(WebAppClassLoading.getProtectedClasses(environment), sameInstance(protect));
|
||||||
|
assertThat(WebAppClassLoading.getHiddenClasses(environment), sameInstance(hide));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnvironmentStringAttributeDefaults()
|
||||||
|
{
|
||||||
|
Environment environment = Environment.get("Test");
|
||||||
|
environment.setAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE, new String[] {"org.protect."});
|
||||||
|
environment.setAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE, new String[] {"org.hide."});
|
||||||
|
|
||||||
|
ClassMatcher protect = WebAppClassLoading.getProtectedClasses(environment);
|
||||||
|
assertThat(protect.size(), is(1));
|
||||||
|
assertThat(Arrays.asList(protect.getPatterns()), contains("org.protect."));
|
||||||
|
assertThat(environment.getAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE), sameInstance(protect));
|
||||||
|
ClassMatcher hide = WebAppClassLoading.getHiddenClasses(environment);
|
||||||
|
assertThat(hide.size(), is(1));
|
||||||
|
assertThat(Arrays.asList(hide.getPatterns()), contains("org.hide."));
|
||||||
|
assertThat(environment.getAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE), sameInstance(hide));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnvironmentProgrammaticDefaults()
|
||||||
|
{
|
||||||
|
Environment environment = Environment.get("Test");
|
||||||
|
WebAppClassLoading.addProtectedClasses(environment, "org.protect.");
|
||||||
|
WebAppClassLoading.addHiddenClasses(environment, "org.hide.");
|
||||||
|
|
||||||
|
ClassMatcher protect = WebAppClassLoading.getProtectedClasses(environment);
|
||||||
|
ClassMatcher hide = WebAppClassLoading.getHiddenClasses(environment);
|
||||||
|
|
||||||
|
assertThat(protect.size(), is(WebAppClassLoading.DEFAULT_PROTECTED_CLASSES.size() + 1));
|
||||||
|
assertThat(protect.getPatterns(), hasItemInArray("org.protect."));
|
||||||
|
for (String pattern : WebAppClassLoading.DEFAULT_PROTECTED_CLASSES)
|
||||||
|
assertThat(protect.getPatterns(), hasItemInArray(pattern));
|
||||||
|
assertThat(environment.getAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE), sameInstance(protect));
|
||||||
|
|
||||||
|
assertThat(hide.size(), is(WebAppClassLoading.DEFAULT_HIDDEN_CLASSES.size() + 1));
|
||||||
|
assertThat(hide.getPatterns(), hasItemInArray("org.hide."));
|
||||||
|
for (String pattern : WebAppClassLoading.DEFAULT_HIDDEN_CLASSES)
|
||||||
|
assertThat(hide.getPatterns(), hasItemInArray(pattern));
|
||||||
|
assertThat(environment.getAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE), sameInstance(hide));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEnvironmentAddPatterns()
|
||||||
|
{
|
||||||
|
Environment environment = Environment.get("Test");
|
||||||
|
ClassMatcher protect = WebAppClassLoading.getProtectedClasses(environment);
|
||||||
|
ClassMatcher hide = WebAppClassLoading.getHiddenClasses(environment);
|
||||||
|
|
||||||
|
assertThat(protect, equalTo(WebAppClassLoading.DEFAULT_PROTECTED_CLASSES));
|
||||||
|
assertThat(hide, equalTo(WebAppClassLoading.DEFAULT_HIDDEN_CLASSES));
|
||||||
|
|
||||||
|
WebAppClassLoading.addProtectedClasses(environment, "org.protect.", "com.protect.");
|
||||||
|
WebAppClassLoading.addHiddenClasses(environment, "org.hide.", "com.hide.");
|
||||||
|
|
||||||
|
assertThat(protect.size(), is(WebAppClassLoading.DEFAULT_PROTECTED_CLASSES.size() + 2));
|
||||||
|
assertThat(protect.getPatterns(), hasItemInArray("org.protect."));
|
||||||
|
assertThat(protect.getPatterns(), hasItemInArray("com.protect."));
|
||||||
|
for (String pattern : WebAppClassLoading.DEFAULT_PROTECTED_CLASSES)
|
||||||
|
assertThat(protect.getPatterns(), hasItemInArray(pattern));
|
||||||
|
assertThat(environment.getAttribute(WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE), sameInstance(protect));
|
||||||
|
|
||||||
|
assertThat(hide.size(), is(WebAppClassLoading.DEFAULT_HIDDEN_CLASSES.size() + 2));
|
||||||
|
assertThat(hide.getPatterns(), hasItemInArray("org.hide."));
|
||||||
|
assertThat(hide.getPatterns(), hasItemInArray("com.hide."));
|
||||||
|
for (String pattern : WebAppClassLoading.DEFAULT_HIDDEN_CLASSES)
|
||||||
|
assertThat(hide.getPatterns(), hasItemInArray(pattern));
|
||||||
|
assertThat(environment.getAttribute(WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE), sameInstance(hide));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -25,7 +25,7 @@ etc/jetty-test-keystore.xml
|
||||||
|
|
||||||
[ini]
|
[ini]
|
||||||
bouncycastle.version?=@bouncycastle.version@
|
bouncycastle.version?=@bouncycastle.version@
|
||||||
jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/bouncycastle/
|
jetty.webapp.addHiddenClasses+=,${jetty.base.uri}/lib/bouncycastle/
|
||||||
jetty.sslContext.keyStorePath?=etc/test-keystore.p12
|
jetty.sslContext.keyStorePath?=etc/test-keystore.p12
|
||||||
jetty.sslContext.keyStoreType?=PKCS12
|
jetty.sslContext.keyStoreType?=PKCS12
|
||||||
jetty.sslContext.keyStorePassword?=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
|
jetty.sslContext.keyStorePassword?=OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4
|
||||||
|
|
|
@ -89,7 +89,7 @@ public class SessionData implements Serializable
|
||||||
//Clazz not loaded by context classloader, but ask if loadable by context classloader,
|
//Clazz not loaded by context classloader, but ask if loadable by context classloader,
|
||||||
//because preferable to use context classloader if possible (eg for deep structures).
|
//because preferable to use context classloader if possible (eg for deep structures).
|
||||||
ClassVisibilityChecker checker = (ClassVisibilityChecker)(contextLoader);
|
ClassVisibilityChecker checker = (ClassVisibilityChecker)(contextLoader);
|
||||||
isContextLoader = (checker.isSystemClass(clazz) && !(checker.isServerClass(clazz)));
|
isContextLoader = (checker.isProtectedClass(clazz) && !(checker.isHiddenClass(clazz)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,810 @@
|
||||||
|
//
|
||||||
|
// ========================================================================
|
||||||
|
// Copyright (c) 1995 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.util;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.AbstractSet;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Predicate;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A matcher for classes based on package and/or location and/or module/
|
||||||
|
* <p>
|
||||||
|
* Performs pattern matching of a class against a set of pattern entries.
|
||||||
|
* A class pattern is a string of one of the forms:<ul>
|
||||||
|
* <li>'org.package.SomeClass' will match a specific class
|
||||||
|
* <li>'org.package.' will match a specific package hierarchy
|
||||||
|
* <li>'org.package.SomeClass$NestedClass ' will match a nested class exactly otherwise.
|
||||||
|
* Nested classes are matched by their containing class. (eg. org.example.MyClass
|
||||||
|
* matches org.example.MyClass$AnyNestedClass)
|
||||||
|
* <li>'file:///some/location/' - A file system directory from which
|
||||||
|
* the class was loaded
|
||||||
|
* <li>'file:///some/location.jar' - The URI of a jar file from which
|
||||||
|
* the class was loaded
|
||||||
|
* <li>'jrt:/modulename' - A Java9 module name</li>
|
||||||
|
* <li>Any of the above patterns preceded by '-' will exclude rather than include the match.
|
||||||
|
* </ul>
|
||||||
|
* When class is initialized from a classpath pattern string, entries
|
||||||
|
* in this string should be separated by ':' (semicolon) or ',' (comma).
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class ClassMatcher extends AbstractSet<String>
|
||||||
|
{
|
||||||
|
public static class Entry
|
||||||
|
{
|
||||||
|
private final String _pattern;
|
||||||
|
private final String _name;
|
||||||
|
private final boolean _inclusive;
|
||||||
|
|
||||||
|
protected Entry(String name, boolean inclusive)
|
||||||
|
{
|
||||||
|
_name = name;
|
||||||
|
_inclusive = inclusive;
|
||||||
|
_pattern = inclusive ? _name : ("-" + _name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPattern()
|
||||||
|
{
|
||||||
|
return _pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName()
|
||||||
|
{
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return _pattern;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode()
|
||||||
|
{
|
||||||
|
return _pattern.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object o)
|
||||||
|
{
|
||||||
|
return (o instanceof Entry) && _pattern.equals(((Entry)o)._pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isInclusive()
|
||||||
|
{
|
||||||
|
return _inclusive;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class PackageEntry extends Entry
|
||||||
|
{
|
||||||
|
protected PackageEntry(String name, boolean inclusive)
|
||||||
|
{
|
||||||
|
super(name, inclusive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ClassEntry extends Entry
|
||||||
|
{
|
||||||
|
protected ClassEntry(String name, boolean inclusive)
|
||||||
|
{
|
||||||
|
super(name, inclusive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class LocationEntry extends Entry
|
||||||
|
{
|
||||||
|
private final Path _path;
|
||||||
|
|
||||||
|
protected LocationEntry(String name, boolean inclusive)
|
||||||
|
{
|
||||||
|
super(name, inclusive);
|
||||||
|
URI uri = URI.create(name);
|
||||||
|
if (!uri.isAbsolute() && !"file".equalsIgnoreCase(uri.getScheme()))
|
||||||
|
throw new IllegalArgumentException("Not a valid file URI: " + name);
|
||||||
|
|
||||||
|
_path = Paths.get(uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path getPath()
|
||||||
|
{
|
||||||
|
return _path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ModuleEntry extends Entry
|
||||||
|
{
|
||||||
|
private final String _module;
|
||||||
|
|
||||||
|
protected ModuleEntry(String name, boolean inclusive)
|
||||||
|
{
|
||||||
|
super(name, inclusive);
|
||||||
|
if (!getName().startsWith("jrt:"))
|
||||||
|
throw new IllegalArgumentException(name);
|
||||||
|
_module = getName().split("/")[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getModule()
|
||||||
|
{
|
||||||
|
return _module;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ByPackage extends AbstractSet<Entry> implements Predicate<String>
|
||||||
|
{
|
||||||
|
private final Index.Mutable<Entry> _entries = new Index.Builder<Entry>()
|
||||||
|
.caseSensitive(true)
|
||||||
|
.mutable()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(String name)
|
||||||
|
{
|
||||||
|
return _entries.getBest(name) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Entry> iterator()
|
||||||
|
{
|
||||||
|
return _entries.keySet().stream().map(_entries::get).iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size()
|
||||||
|
{
|
||||||
|
return _entries.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty()
|
||||||
|
{
|
||||||
|
return _entries.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean add(Entry entry)
|
||||||
|
{
|
||||||
|
String name = entry.getName();
|
||||||
|
if (entry instanceof ClassEntry)
|
||||||
|
name += "$";
|
||||||
|
else if (!(entry instanceof PackageEntry))
|
||||||
|
throw new IllegalArgumentException(entry.toString());
|
||||||
|
else if (".".equals(name))
|
||||||
|
name = "";
|
||||||
|
|
||||||
|
if (_entries.get(name) != null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return _entries.put(name, entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean remove(Object entry)
|
||||||
|
{
|
||||||
|
if (!(entry instanceof Entry))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return _entries.remove(((Entry)entry).getName()) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear()
|
||||||
|
{
|
||||||
|
_entries.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ByClass extends HashSet<Entry> implements Predicate<String>
|
||||||
|
{
|
||||||
|
private final Map<String, Entry> _entries = new HashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(String name)
|
||||||
|
{
|
||||||
|
return _entries.containsKey(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Entry> iterator()
|
||||||
|
{
|
||||||
|
return _entries.values().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size()
|
||||||
|
{
|
||||||
|
return _entries.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean add(Entry entry)
|
||||||
|
{
|
||||||
|
if (!(entry instanceof ClassEntry))
|
||||||
|
throw new IllegalArgumentException(entry.toString());
|
||||||
|
return _entries.put(entry.getName(), entry) == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean remove(Object entry)
|
||||||
|
{
|
||||||
|
if (!(entry instanceof Entry))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return _entries.remove(((Entry)entry).getName()) != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ByPackageOrName extends AbstractSet<Entry> implements Predicate<String>
|
||||||
|
{
|
||||||
|
private final ByClass _byClass = new ByClass();
|
||||||
|
private final ByPackage _byPackage = new ByPackage();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(String name)
|
||||||
|
{
|
||||||
|
return _byPackage.test(name) || _byClass.test(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Entry> iterator()
|
||||||
|
{
|
||||||
|
// by package contains all entries (classes are also $ packages).
|
||||||
|
return _byPackage.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size()
|
||||||
|
{
|
||||||
|
return _byPackage.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean add(Entry entry)
|
||||||
|
{
|
||||||
|
if (entry instanceof PackageEntry)
|
||||||
|
return _byPackage.add(entry);
|
||||||
|
|
||||||
|
if (entry instanceof ClassEntry)
|
||||||
|
{
|
||||||
|
// Add class name to packages also as classes act
|
||||||
|
// as packages for nested classes.
|
||||||
|
boolean added = _byPackage.add(entry);
|
||||||
|
added = _byClass.add(entry) || added;
|
||||||
|
return added;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new IllegalArgumentException();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean remove(Object o)
|
||||||
|
{
|
||||||
|
if (!(o instanceof Entry))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
boolean removedPackage = _byPackage.remove(o);
|
||||||
|
boolean removedClass = _byClass.remove(o);
|
||||||
|
|
||||||
|
return removedPackage || removedClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear()
|
||||||
|
{
|
||||||
|
_byPackage.clear();
|
||||||
|
_byClass.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ByLocation extends HashSet<Entry> implements Predicate<URI>
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public boolean test(URI uri)
|
||||||
|
{
|
||||||
|
if ((uri == null) || (!uri.isAbsolute()))
|
||||||
|
return false;
|
||||||
|
if (!uri.getScheme().equals("file"))
|
||||||
|
return false;
|
||||||
|
Path path = Paths.get(uri);
|
||||||
|
|
||||||
|
for (Entry entry : this)
|
||||||
|
{
|
||||||
|
if (!(entry instanceof LocationEntry))
|
||||||
|
throw new IllegalStateException();
|
||||||
|
|
||||||
|
Path entryPath = ((LocationEntry)entry).getPath();
|
||||||
|
|
||||||
|
if (Files.isDirectory(entryPath))
|
||||||
|
{
|
||||||
|
if (path.startsWith(entryPath))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (Files.isSameFile(path, entryPath))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (IOException ignore)
|
||||||
|
{
|
||||||
|
// this means there is a FileSystem issue preventing comparison.
|
||||||
|
// Use old technique
|
||||||
|
if (path.equals(entryPath))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ByModule extends HashSet<Entry> implements Predicate<URI>
|
||||||
|
{
|
||||||
|
private final Index.Mutable<Entry> _entries = new Index.Builder<Entry>()
|
||||||
|
.caseSensitive(true)
|
||||||
|
.mutable()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(URI uri)
|
||||||
|
{
|
||||||
|
if ((uri == null) || (!uri.isAbsolute()))
|
||||||
|
return false;
|
||||||
|
if (!uri.getScheme().equalsIgnoreCase("jrt"))
|
||||||
|
return false;
|
||||||
|
String module = uri.getPath();
|
||||||
|
int end = module.indexOf('/', 1);
|
||||||
|
if (end < 1)
|
||||||
|
end = module.length();
|
||||||
|
return _entries.get(module, 1, end - 1) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Entry> iterator()
|
||||||
|
{
|
||||||
|
return _entries.keySet().stream().map(_entries::get).iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size()
|
||||||
|
{
|
||||||
|
return _entries.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean add(Entry entry)
|
||||||
|
{
|
||||||
|
if (!(entry instanceof ModuleEntry))
|
||||||
|
throw new IllegalArgumentException(entry.toString());
|
||||||
|
String module = ((ModuleEntry)entry).getModule();
|
||||||
|
|
||||||
|
if (_entries.get(module) != null)
|
||||||
|
return false;
|
||||||
|
_entries.put(module, entry);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean remove(Object entry)
|
||||||
|
{
|
||||||
|
if (!(entry instanceof Entry))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return _entries.remove(((Entry)entry).getName()) != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ByLocationOrModule extends AbstractSet<Entry> implements Predicate<URI>
|
||||||
|
{
|
||||||
|
private final ByLocation _byLocation = new ByLocation();
|
||||||
|
private final ByModule _byModule = new ByModule();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean test(URI name)
|
||||||
|
{
|
||||||
|
if ((name == null) || (!name.isAbsolute()))
|
||||||
|
return false;
|
||||||
|
return _byLocation.test(name) || _byModule.test(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<Entry> iterator()
|
||||||
|
{
|
||||||
|
Set<Entry> entries = new HashSet<>();
|
||||||
|
entries.addAll(_byLocation);
|
||||||
|
entries.addAll(_byModule);
|
||||||
|
return entries.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size()
|
||||||
|
{
|
||||||
|
return _byLocation.size() + _byModule.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean add(Entry entry)
|
||||||
|
{
|
||||||
|
if (entry instanceof LocationEntry)
|
||||||
|
return _byLocation.add(entry);
|
||||||
|
if (entry instanceof ModuleEntry)
|
||||||
|
return _byModule.add(entry);
|
||||||
|
|
||||||
|
throw new IllegalArgumentException(entry.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean remove(Object o)
|
||||||
|
{
|
||||||
|
if (o instanceof LocationEntry)
|
||||||
|
return _byLocation.remove(o);
|
||||||
|
if (o instanceof ModuleEntry)
|
||||||
|
return _byModule.remove(o);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear()
|
||||||
|
{
|
||||||
|
_byLocation.clear();
|
||||||
|
_byModule.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected final Map<String, Entry> _entries;
|
||||||
|
protected final IncludeExcludeSet<Entry, String> _patterns;
|
||||||
|
protected final IncludeExcludeSet<Entry, URI> _locations;
|
||||||
|
|
||||||
|
protected ClassMatcher(Map<String, Entry> entries, IncludeExcludeSet<Entry, String> patterns, IncludeExcludeSet<Entry, URI> locations)
|
||||||
|
{
|
||||||
|
_entries = entries;
|
||||||
|
_patterns = patterns == null ? new IncludeExcludeSet<>(ByPackageOrName.class) : patterns;
|
||||||
|
_locations = locations == null ? new IncludeExcludeSet<>(ByLocationOrModule.class) : locations;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ClassMatcher(Map<String, Entry> entries)
|
||||||
|
{
|
||||||
|
this(entries, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassMatcher()
|
||||||
|
{
|
||||||
|
this(new HashMap<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassMatcher(ClassMatcher patterns)
|
||||||
|
{
|
||||||
|
this(new HashMap<>());
|
||||||
|
if (patterns != null)
|
||||||
|
setAll(patterns.getPatterns());
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassMatcher(String... patterns)
|
||||||
|
{
|
||||||
|
this(new HashMap<>());
|
||||||
|
if (patterns != null && patterns.length > 0)
|
||||||
|
setAll(patterns);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassMatcher(String pattern)
|
||||||
|
{
|
||||||
|
this(new HashMap<>());
|
||||||
|
add(pattern);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ClassMatcher asImmutable()
|
||||||
|
{
|
||||||
|
return new ClassMatcher(Map.copyOf(_entries),
|
||||||
|
_patterns.asImmutable(),
|
||||||
|
_locations.asImmutable());
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean include(String name)
|
||||||
|
{
|
||||||
|
if (name == null)
|
||||||
|
return false;
|
||||||
|
return add(newEntry(name, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean include(String... name)
|
||||||
|
{
|
||||||
|
boolean added = false;
|
||||||
|
for (String n : name)
|
||||||
|
{
|
||||||
|
if (n != null)
|
||||||
|
added = add(newEntry(n, true)) || added;
|
||||||
|
}
|
||||||
|
return added;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean exclude(String name)
|
||||||
|
{
|
||||||
|
if (name == null)
|
||||||
|
return false;
|
||||||
|
return add(newEntry(name, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean exclude(String... name)
|
||||||
|
{
|
||||||
|
boolean added = false;
|
||||||
|
for (String n : name)
|
||||||
|
{
|
||||||
|
if (n != null)
|
||||||
|
added = add(newEntry(n, false)) || added;
|
||||||
|
}
|
||||||
|
return added;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean add(String pattern)
|
||||||
|
{
|
||||||
|
if (pattern == null)
|
||||||
|
return false;
|
||||||
|
return add(newEntry(pattern));
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean add(String... pattern)
|
||||||
|
{
|
||||||
|
boolean added = false;
|
||||||
|
for (String p : pattern)
|
||||||
|
{
|
||||||
|
if (p != null)
|
||||||
|
added = add(newEntry(p)) || added;
|
||||||
|
}
|
||||||
|
return added;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean add(Entry entry)
|
||||||
|
{
|
||||||
|
if (_entries.containsKey(entry.getPattern()))
|
||||||
|
return false;
|
||||||
|
_entries.put(entry.getPattern(), entry);
|
||||||
|
|
||||||
|
if (entry instanceof LocationEntry || entry instanceof ModuleEntry)
|
||||||
|
{
|
||||||
|
if (entry.isInclusive())
|
||||||
|
_locations.include(entry);
|
||||||
|
else
|
||||||
|
_locations.exclude(entry);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (entry.isInclusive())
|
||||||
|
_patterns.include(entry);
|
||||||
|
else
|
||||||
|
_patterns.exclude(entry);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Entry newEntry(String pattern)
|
||||||
|
{
|
||||||
|
if (pattern.startsWith("-"))
|
||||||
|
return newEntry(pattern.substring(1), false);
|
||||||
|
return newEntry(pattern, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Entry newEntry(String name, boolean inclusive)
|
||||||
|
{
|
||||||
|
if (name.startsWith("-"))
|
||||||
|
throw new IllegalStateException(name);
|
||||||
|
if (name.startsWith("file:"))
|
||||||
|
return new LocationEntry(name, inclusive);
|
||||||
|
if (name.startsWith("jrt:"))
|
||||||
|
return new ModuleEntry(name, inclusive);
|
||||||
|
if (name.endsWith("."))
|
||||||
|
return new PackageEntry(name, inclusive);
|
||||||
|
return new ClassEntry(name, inclusive);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean remove(Object o)
|
||||||
|
{
|
||||||
|
if (!(o instanceof String pattern))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Entry entry = _entries.remove(pattern);
|
||||||
|
if (entry == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
List<Entry> saved = new ArrayList<>(_entries.values());
|
||||||
|
clear();
|
||||||
|
for (Entry e : saved)
|
||||||
|
{
|
||||||
|
add(e);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear()
|
||||||
|
{
|
||||||
|
_entries.clear();
|
||||||
|
_patterns.clear();
|
||||||
|
_locations.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Iterator<String> iterator()
|
||||||
|
{
|
||||||
|
return _entries.keySet().iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size()
|
||||||
|
{
|
||||||
|
return _entries.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the matcher by parsing each classpath pattern in an array
|
||||||
|
*
|
||||||
|
* @param classes array of classpath patterns
|
||||||
|
*/
|
||||||
|
private void setAll(String[] classes)
|
||||||
|
{
|
||||||
|
_entries.clear();
|
||||||
|
addAll(classes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add array of classpath patterns.
|
||||||
|
* @param classes array of classpath patterns
|
||||||
|
*/
|
||||||
|
private void addAll(String[] classes)
|
||||||
|
{
|
||||||
|
if (classes != null)
|
||||||
|
addAll(Arrays.asList(classes));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array of classpath patterns
|
||||||
|
*/
|
||||||
|
public String[] getPatterns()
|
||||||
|
{
|
||||||
|
return toArray(new String[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array of inclusive classpath patterns
|
||||||
|
*/
|
||||||
|
public String[] getInclusions()
|
||||||
|
{
|
||||||
|
return _entries.values().stream().filter(Entry::isInclusive).map(Entry::getName).toArray(String[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array of excluded classpath patterns (without '-' prefix)
|
||||||
|
*/
|
||||||
|
public String[] getExclusions()
|
||||||
|
{
|
||||||
|
return _entries.values().stream().filter(e -> !e.isInclusive()).map(Entry::getName).toArray(String[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Match the class name against the pattern
|
||||||
|
*
|
||||||
|
* @param name name of the class to match
|
||||||
|
* @return true if class matches the pattern
|
||||||
|
*/
|
||||||
|
public boolean match(String name)
|
||||||
|
{
|
||||||
|
return _patterns.test(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Match the class name against the pattern
|
||||||
|
*
|
||||||
|
* @param clazz A class to try to match
|
||||||
|
* @return true if class matches the pattern
|
||||||
|
*/
|
||||||
|
public boolean match(Class<?> clazz)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return combine(_patterns, clazz.getName(), _locations, () -> TypeUtil.getLocationOfClass(clazz));
|
||||||
|
}
|
||||||
|
catch (Exception ignored)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean match(String name, URL url)
|
||||||
|
{
|
||||||
|
if (url == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Strip class suffix for name matching
|
||||||
|
if (name.endsWith(".class"))
|
||||||
|
name = name.substring(0, name.length() - 6);
|
||||||
|
|
||||||
|
// Treat path elements as packages for name matching
|
||||||
|
name = StringUtil.replace(name, '/', '.');
|
||||||
|
|
||||||
|
return combine(_patterns, name, _locations, () ->
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return URIUtil.unwrapContainer(url.toURI());
|
||||||
|
}
|
||||||
|
catch (URISyntaxException ignored)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Match a class against inclusions and exclusions by name and location.
|
||||||
|
* Name based checks are performed before location checks. For a class to match,
|
||||||
|
* it must not be excluded by either name or location, and must either be explicitly
|
||||||
|
* included, or for there to be no inclusions. In the case where the location
|
||||||
|
* of the class is null, it will match if it is included by name, or
|
||||||
|
* if there are no location exclusions.
|
||||||
|
*
|
||||||
|
* @param names configured inclusions and exclusions by name
|
||||||
|
* @param name the name to check
|
||||||
|
* @param locations configured inclusions and exclusions by location
|
||||||
|
* @param location the location of the class (can be null)
|
||||||
|
* @return true if the class is not excluded but is included, or there are
|
||||||
|
* no inclusions. False otherwise.
|
||||||
|
*/
|
||||||
|
static boolean combine(IncludeExcludeSet<Entry, String> names, String name, IncludeExcludeSet<Entry, URI> locations, Supplier<URI> location)
|
||||||
|
{
|
||||||
|
// check the name set
|
||||||
|
Boolean byName = names.isIncludedAndNotExcluded(name);
|
||||||
|
|
||||||
|
// If we excluded by name, then no match
|
||||||
|
if (Boolean.FALSE == byName)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// check the location set
|
||||||
|
URI uri = location.get();
|
||||||
|
Boolean byLocation = uri == null ? null : locations.isIncludedAndNotExcluded(uri);
|
||||||
|
|
||||||
|
// If we excluded by location or couldn't check location exclusion, then no match
|
||||||
|
if (Boolean.FALSE == byLocation || (locations.hasExcludes() && uri == null))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// If there are includes, then we must be included to match.
|
||||||
|
if (names.hasIncludes() || locations.hasIncludes())
|
||||||
|
return byName == Boolean.TRUE || byLocation == Boolean.TRUE;
|
||||||
|
|
||||||
|
// Otherwise there are no includes and it was not excluded, so match
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,13 +14,33 @@
|
||||||
package org.eclipse.jetty.util;
|
package org.eclipse.jetty.util;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ClassVisibilityChecker
|
|
||||||
*
|
|
||||||
* Interface to be implemented by classes capable of checking class visibility
|
* Interface to be implemented by classes capable of checking class visibility
|
||||||
* for a context.
|
* for a context.
|
||||||
*/
|
*/
|
||||||
public interface ClassVisibilityChecker
|
public interface ClassVisibilityChecker
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
* Is the class a Protected (System) Class.
|
||||||
|
* A System class is a class that is visible to a webapplication,
|
||||||
|
* but that cannot be overridden by the contents of WEB-INF/lib or
|
||||||
|
* WEB-INF/classes
|
||||||
|
*
|
||||||
|
* @param clazz The fully qualified name of the class.
|
||||||
|
* @return True if the class is a system class.
|
||||||
|
*/
|
||||||
|
boolean isProtectedClass(Class<?> clazz);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the class a Hidden (Server) Class.
|
||||||
|
* A Server class is a class that is part of the implementation of
|
||||||
|
* the server and is NIT visible to a webapplication. The web
|
||||||
|
* application may provide it's own implementation of the class,
|
||||||
|
* to be loaded from WEB-INF/lib or WEB-INF/classes
|
||||||
|
*
|
||||||
|
* @param clazz The fully qualified name of the class.
|
||||||
|
* @return True if the class is a server class.
|
||||||
|
*/
|
||||||
|
boolean isHiddenClass(Class<?> clazz);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the class a System Class.
|
* Is the class a System Class.
|
||||||
|
@ -30,8 +50,13 @@ public interface ClassVisibilityChecker
|
||||||
*
|
*
|
||||||
* @param clazz The fully qualified name of the class.
|
* @param clazz The fully qualified name of the class.
|
||||||
* @return True if the class is a system class.
|
* @return True if the class is a system class.
|
||||||
|
* @deprecated use {@link #isProtectedClass(Class)}
|
||||||
*/
|
*/
|
||||||
boolean isSystemClass(Class<?> clazz);
|
@Deprecated (forRemoval = true, since = "12.0.9")
|
||||||
|
default boolean isSystemClass(Class<?> clazz)
|
||||||
|
{
|
||||||
|
return isProtectedClass(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is the class a Server Class.
|
* Is the class a Server Class.
|
||||||
|
@ -42,6 +67,11 @@ public interface ClassVisibilityChecker
|
||||||
*
|
*
|
||||||
* @param clazz The fully qualified name of the class.
|
* @param clazz The fully qualified name of the class.
|
||||||
* @return True if the class is a server class.
|
* @return True if the class is a server class.
|
||||||
|
* @deprecated use {@link #isHiddenClass(Class)}
|
||||||
*/
|
*/
|
||||||
boolean isServerClass(Class<?> clazz);
|
@Deprecated (forRemoval = true, since = "12.0.9")
|
||||||
|
default boolean isServerClass(Class<?> clazz)
|
||||||
|
{
|
||||||
|
return isHiddenClass(clazz);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,17 +11,15 @@
|
||||||
// ========================================================================
|
// ========================================================================
|
||||||
//
|
//
|
||||||
|
|
||||||
package org.eclipse.jetty.ee10.webapp;
|
package org.eclipse.jetty.util;
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.eclipse.jetty.ee10.webapp.ClassMatcher.ByLocationOrModule;
|
import org.eclipse.jetty.util.ClassMatcher.ByLocationOrModule;
|
||||||
import org.eclipse.jetty.ee10.webapp.ClassMatcher.ByPackageOrName;
|
import org.eclipse.jetty.util.ClassMatcher.ByPackageOrName;
|
||||||
import org.eclipse.jetty.ee10.webapp.ClassMatcher.Entry;
|
import org.eclipse.jetty.util.ClassMatcher.Entry;
|
||||||
import org.eclipse.jetty.util.IncludeExcludeSet;
|
|
||||||
import org.eclipse.jetty.util.TypeUtil;
|
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
|
@ -17,6 +17,7 @@
|
||||||
<module>jetty-client</module>
|
<module>jetty-client</module>
|
||||||
<module>jetty-demos</module>
|
<module>jetty-demos</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-http-spi</module>
|
<module>jetty-http-spi</module>
|
||||||
|
|
|
@ -158,7 +158,7 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH
|
||||||
|
|
||||||
//try environment scope next
|
//try environment scope next
|
||||||
if (!bound)
|
if (!bound)
|
||||||
bound = NamingEntryUtil.bindToENC(ServletContextHandler.__environment.getName(), name, mappedName);
|
bound = NamingEntryUtil.bindToENC(ServletContextHandler.ENVIRONMENT.getName(), name, mappedName);
|
||||||
|
|
||||||
//try Server scope next
|
//try Server scope next
|
||||||
if (!bound)
|
if (!bound)
|
||||||
|
@ -313,7 +313,7 @@ public class ResourceAnnotationHandler extends AbstractIntrospectableAnnotationH
|
||||||
|
|
||||||
//try the environment's scope
|
//try the environment's scope
|
||||||
if (!bound)
|
if (!bound)
|
||||||
bound = NamingEntryUtil.bindToENC(ServletContextHandler.__environment.getName(), name, mappedName);
|
bound = NamingEntryUtil.bindToENC(ServletContextHandler.ENVIRONMENT.getName(), name, mappedName);
|
||||||
|
|
||||||
//try the server's scope
|
//try the server's scope
|
||||||
if (!bound)
|
if (!bound)
|
||||||
|
|
|
@ -9,7 +9,7 @@ org.eclipse.jetty.ee10.servlet.WebApplicationContext object
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<Configure class="org.eclipse.jetty.ee10.webapp.WebAppContext">
|
<Configure class="org.eclipse.jetty.ee10.webapp.WebAppContext">
|
||||||
<Get name="ServerClassMatcher">
|
<Get name="HiddenClassMatcher">
|
||||||
<Call name="exclude">
|
<Call name="exclude">
|
||||||
<Arg>
|
<Arg>
|
||||||
<Array type="String">
|
<Array type="String">
|
||||||
|
|
|
@ -54,7 +54,7 @@ public class ProxyWebAppTest
|
||||||
// This is a pieced together WebApp.
|
// This is a pieced together WebApp.
|
||||||
// We don't have a valid WEB-INF/lib to rely on at this point.
|
// We don't have a valid WEB-INF/lib to rely on at this point.
|
||||||
// So, open up server classes here, for purposes of this testcase.
|
// So, open up server classes here, for purposes of this testcase.
|
||||||
webapp.getServerClassMatcher().add("-org.eclipse.jetty.ee10.proxy.");
|
webapp.getHiddenClassMatcher().add("-org.eclipse.jetty.ee10.proxy.");
|
||||||
webapp.setWar(MavenTestingUtils.getProjectDirPath("src/main/webapp").toString());
|
webapp.setWar(MavenTestingUtils.getProjectDirPath("src/main/webapp").toString());
|
||||||
webapp.setExtraClasspath(MavenTestingUtils.getTargetPath().resolve("test-classes").toString());
|
webapp.setExtraClasspath(MavenTestingUtils.getTargetPath().resolve("test-classes").toString());
|
||||||
server.setHandler(webapp);
|
server.setHandler(webapp);
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<Configure class="org.eclipse.jetty.ee10.webapp.WebAppContext">
|
<Configure class="org.eclipse.jetty.ee10.webapp.WebAppContext">
|
||||||
<Call name="addServerClassMatcher">
|
<Call name="addServerClassMatcher">
|
||||||
<Arg>
|
<Arg>
|
||||||
<New class="org.eclipse.jetty.ee10.webapp.ClassMatcher">
|
<New class="org.eclipse.jetty.util.ClassMatcher">
|
||||||
<Arg>
|
<Arg>
|
||||||
<Array type="java.lang.String">
|
<Array type="java.lang.String">
|
||||||
<Item>-org.eclipse.jetty.util.Decorator</Item>
|
<Item>-org.eclipse.jetty.util.Decorator</Item>
|
||||||
|
|
|
@ -234,6 +234,7 @@ public class TestOSGiUtil
|
||||||
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-jndi").versionAsInProject().start());
|
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-jndi").versionAsInProject().start());
|
||||||
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-osgi").versionAsInProject().start());
|
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-osgi").versionAsInProject().start());
|
||||||
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-client").versionAsInProject().start());
|
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-client").versionAsInProject().start());
|
||||||
|
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-ee").versionAsInProject().start());
|
||||||
res.add(mavenBundle().groupId("org.eclipse.jetty.ee10").artifactId("jetty-ee10-servlet").versionAsInProject().start());
|
res.add(mavenBundle().groupId("org.eclipse.jetty.ee10").artifactId("jetty-ee10-servlet").versionAsInProject().start());
|
||||||
res.add(mavenBundle().groupId("org.eclipse.jetty.ee10").artifactId("jetty-ee10-webapp").versionAsInProject().start());
|
res.add(mavenBundle().groupId("org.eclipse.jetty.ee10").artifactId("jetty-ee10-webapp").versionAsInProject().start());
|
||||||
res.add(mavenBundle().groupId("org.eclipse.jetty.ee10").artifactId("jetty-ee10-servlets").versionAsInProject().start());
|
res.add(mavenBundle().groupId("org.eclipse.jetty.ee10").artifactId("jetty-ee10-servlets").versionAsInProject().start());
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.ee10.plus.webapp;
|
package org.eclipse.jetty.ee10.plus.webapp;
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.naming.Context;
|
import javax.naming.Context;
|
||||||
import javax.naming.InitialContext;
|
import javax.naming.InitialContext;
|
||||||
|
@ -208,8 +207,8 @@ public class EnvConfiguration extends AbstractConfiguration
|
||||||
LOG.debug("Binding env entries from the server scope");
|
LOG.debug("Binding env entries from the server scope");
|
||||||
doBindings(envCtx, context.getServer());
|
doBindings(envCtx, context.getServer());
|
||||||
|
|
||||||
LOG.debug("Binding env entries from environment {} scope", ServletContextHandler.__environment.getName());
|
LOG.debug("Binding env entries from environment {} scope", ServletContextHandler.ENVIRONMENT.getName());
|
||||||
doBindings(envCtx, ServletContextHandler.__environment.getName());
|
doBindings(envCtx, ServletContextHandler.ENVIRONMENT.getName());
|
||||||
|
|
||||||
LOG.debug("Binding env entries from the context scope");
|
LOG.debug("Binding env entries from the context scope");
|
||||||
doBindings(envCtx, context);
|
doBindings(envCtx, context);
|
||||||
|
|
|
@ -83,13 +83,13 @@ public class PlusConfiguration extends AbstractConfiguration
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Transaction.bindTransactionToENC(ServletContextHandler.__environment.getName());
|
Transaction.bindTransactionToENC(ServletContextHandler.ENVIRONMENT.getName());
|
||||||
}
|
}
|
||||||
catch (NameNotFoundException e)
|
catch (NameNotFoundException e)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
org.eclipse.jetty.plus.jndi.Transaction.bindTransactionToENC(ServletContextHandler.__environment.getName());
|
org.eclipse.jetty.plus.jndi.Transaction.bindTransactionToENC(ServletContextHandler.ENVIRONMENT.getName());
|
||||||
}
|
}
|
||||||
catch (NameNotFoundException x)
|
catch (NameNotFoundException x)
|
||||||
{
|
{
|
||||||
|
|
|
@ -129,7 +129,7 @@ public class PlusDescriptorProcessorTest
|
||||||
context.setConfigurations(new Configuration[]{new PlusConfiguration(), new EnvConfiguration()});
|
context.setConfigurations(new Configuration[]{new PlusConfiguration(), new EnvConfiguration()});
|
||||||
context.preConfigure();
|
context.preConfigure();
|
||||||
context.setClassLoader(new WebAppClassLoader(Thread.currentThread().getContextClassLoader(), context));
|
context.setClassLoader(new WebAppClassLoader(Thread.currentThread().getContextClassLoader(), context));
|
||||||
context.getServerClassMatcher().exclude("org.eclipse.jetty.ee10.plus.webapp."); //need visbility of the TestInjections class
|
context.getHiddenClassMatcher().exclude("org.eclipse.jetty.ee10.plus.webapp."); //need visbility of the TestInjections class
|
||||||
ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
|
ClassLoader oldLoader = Thread.currentThread().getContextClassLoader();
|
||||||
Thread.currentThread().setContextClassLoader(context.getClassLoader());
|
Thread.currentThread().setContextClassLoader(context.getClassLoader());
|
||||||
Context icontext = new InitialContext();
|
Context icontext = new InitialContext();
|
||||||
|
|
|
@ -89,7 +89,7 @@ public class TestQuickStart
|
||||||
WebAppContext webapp = new WebAppContext();
|
WebAppContext webapp = new WebAppContext();
|
||||||
webapp.setBaseResourceAsPath(testDir.toPath());
|
webapp.setBaseResourceAsPath(testDir.toPath());
|
||||||
webapp.addConfiguration(new QuickStartConfiguration());
|
webapp.addConfiguration(new QuickStartConfiguration());
|
||||||
webapp.getServerClassMatcher().exclude("org.eclipse.jetty.ee10.quickstart.");
|
webapp.getHiddenClassMatcher().exclude("org.eclipse.jetty.ee10.quickstart.");
|
||||||
webapp.setAttribute(QuickStartConfiguration.MODE, QuickStartConfiguration.Mode.QUICKSTART);
|
webapp.setAttribute(QuickStartConfiguration.MODE, QuickStartConfiguration.Mode.QUICKSTART);
|
||||||
//add in the servlet
|
//add in the servlet
|
||||||
webapp.getServletHandler().addServlet(fooHolder);
|
webapp.getServletHandler().addServlet(fooHolder);
|
||||||
|
@ -139,7 +139,7 @@ public class TestQuickStart
|
||||||
webapp.addConfiguration(new QuickStartConfiguration());
|
webapp.addConfiguration(new QuickStartConfiguration());
|
||||||
webapp.setAttribute(QuickStartConfiguration.MODE, QuickStartConfiguration.Mode.QUICKSTART);
|
webapp.setAttribute(QuickStartConfiguration.MODE, QuickStartConfiguration.Mode.QUICKSTART);
|
||||||
webapp.setBaseResourceAsPath(testDir.toPath());
|
webapp.setBaseResourceAsPath(testDir.toPath());
|
||||||
webapp.getServerClassMatcher().exclude("org.eclipse.jetty.ee10.quickstart.");
|
webapp.getHiddenClassMatcher().exclude("org.eclipse.jetty.ee10.quickstart.");
|
||||||
server.setHandler(webapp);
|
server.setHandler(webapp);
|
||||||
|
|
||||||
server.setDryRun(false);
|
server.setDryRun(false);
|
||||||
|
@ -180,7 +180,7 @@ public class TestQuickStart
|
||||||
webapp.addConfiguration(new QuickStartConfiguration());
|
webapp.addConfiguration(new QuickStartConfiguration());
|
||||||
webapp.setAttribute(QuickStartConfiguration.MODE, QuickStartConfiguration.Mode.QUICKSTART);
|
webapp.setAttribute(QuickStartConfiguration.MODE, QuickStartConfiguration.Mode.QUICKSTART);
|
||||||
webapp.setBaseResourceAsPath(testDir.toPath());
|
webapp.setBaseResourceAsPath(testDir.toPath());
|
||||||
webapp.getServerClassMatcher().exclude("org.eclipse.jetty.ee10.quickstart.");
|
webapp.getHiddenClassMatcher().exclude("org.eclipse.jetty.ee10.quickstart.");
|
||||||
server.setHandler(webapp);
|
server.setHandler(webapp);
|
||||||
|
|
||||||
server.setDryRun(false);
|
server.setDryRun(false);
|
||||||
|
@ -255,7 +255,7 @@ public class TestQuickStart
|
||||||
//a freshly applied context xml
|
//a freshly applied context xml
|
||||||
quickstart = new WebAppContext();
|
quickstart = new WebAppContext();
|
||||||
//need visibility of FooServlet, FooFilter, FooContextListener when we quickstart
|
//need visibility of FooServlet, FooFilter, FooContextListener when we quickstart
|
||||||
quickstart.getServerClassMatcher().exclude("org.eclipse.jetty.ee10.quickstart.");
|
quickstart.getHiddenClassMatcher().exclude("org.eclipse.jetty.ee10.quickstart.");
|
||||||
quickstart.addConfiguration(new QuickStartConfiguration());
|
quickstart.addConfiguration(new QuickStartConfiguration());
|
||||||
quickstart.setWar(testDir.toURI().toURL().toExternalForm());
|
quickstart.setWar(testDir.toURI().toURL().toExternalForm());
|
||||||
quickstart.setDescriptor(MavenTestingUtils.getTestResourceFile("web.xml").getAbsolutePath());
|
quickstart.setDescriptor(MavenTestingUtils.getTestResourceFile("web.xml").getAbsolutePath());
|
||||||
|
|
|
@ -131,7 +131,12 @@ import static jakarta.servlet.ServletContext.TEMPDIR;
|
||||||
public class ServletContextHandler extends ContextHandler
|
public class ServletContextHandler extends ContextHandler
|
||||||
{
|
{
|
||||||
private static final Logger LOG = LoggerFactory.getLogger(ServletContextHandler.class);
|
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.
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "12.0.9", forRemoval = true)
|
||||||
|
public static final Environment __environment = ENVIRONMENT;
|
||||||
public static final Class<?>[] SERVLET_LISTENER_TYPES =
|
public static final Class<?>[] SERVLET_LISTENER_TYPES =
|
||||||
{
|
{
|
||||||
ServletContextListener.class,
|
ServletContextListener.class,
|
||||||
|
|
|
@ -29,7 +29,6 @@ import org.eclipse.jetty.ee10.webapp.WebAppContext;
|
||||||
import org.eclipse.jetty.server.LocalConnector;
|
import org.eclipse.jetty.server.LocalConnector;
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
import org.junit.jupiter.api.Assumptions;
|
import org.junit.jupiter.api.Assumptions;
|
||||||
import org.junit.jupiter.api.Disabled;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.ValueSource;
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
@ -204,8 +203,8 @@ public class EmbeddedWeldTest
|
||||||
webapp.addServletContainerInitializer(new org.jboss.weld.environment.servlet.EnhancedListener());
|
webapp.addServletContainerInitializer(new org.jboss.weld.environment.servlet.EnhancedListener());
|
||||||
|
|
||||||
String pkg = EmbeddedWeldTest.class.getPackage().getName();
|
String pkg = EmbeddedWeldTest.class.getPackage().getName();
|
||||||
webapp.getServerClassMatcher().add("-" + pkg + ".");
|
webapp.getHiddenClassMatcher().add("-" + pkg + ".");
|
||||||
webapp.getSystemClassMatcher().add(pkg + ".");
|
webapp.getProtectedClassMatcher().add(pkg + ".");
|
||||||
|
|
||||||
webapp.addServlet(GreetingsServlet.class, "/greet");
|
webapp.addServlet(GreetingsServlet.class, "/greet");
|
||||||
webapp.addFilter(MyFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
|
webapp.addFilter(MyFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
|
||||||
|
@ -240,8 +239,8 @@ public class EmbeddedWeldTest
|
||||||
|
|
||||||
// This is ugly but needed for maven for testing in a overlaid war pom
|
// This is ugly but needed for maven for testing in a overlaid war pom
|
||||||
String pkg = EmbeddedWeldTest.class.getPackage().getName();
|
String pkg = EmbeddedWeldTest.class.getPackage().getName();
|
||||||
webapp.getServerClassMatcher().add("-" + pkg + ".");
|
webapp.getHiddenClassMatcher().add("-" + pkg + ".");
|
||||||
webapp.getSystemClassMatcher().add(pkg + ".");
|
webapp.getProtectedClassMatcher().add(pkg + ".");
|
||||||
|
|
||||||
webapp.getServletHandler().addListener(new ListenerHolder(MyContextListener.class));
|
webapp.getServletHandler().addListener(new ListenerHolder(MyContextListener.class));
|
||||||
webapp.addFilter(MyFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
|
webapp.addFilter(MyFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
<Configure class="org.eclipse.jetty.ee10.webapp.WebAppContext">
|
<Configure class="org.eclipse.jetty.ee10.webapp.WebAppContext">
|
||||||
<Set name="contextPath">/rfc2616-webapp</Set>
|
<Set name="contextPath">/rfc2616-webapp</Set>
|
||||||
<Set name="war"><Property name="test.webapps" default="target/webapps" />/ee10-test-rfc2616.war</Set>
|
<Set name="war"><Property name="test.webapps" default="target/webapps" />/ee10-test-rfc2616.war</Set>
|
||||||
<Get name="systemClassMatcher">
|
<Get name="ProtectedClassMatcher">
|
||||||
<Call name="add"><Arg>org.slf4j.</Arg></Call>
|
<Call name="add"><Arg>org.slf4j.</Arg></Call>
|
||||||
<Call name="add"><Arg>org.eclipse.jetty.logging.</Arg></Call>
|
<Call name="add"><Arg>org.eclipse.jetty.logging.</Arg></Call>
|
||||||
</Get>
|
</Get>
|
||||||
<Get name="serverClassMatcher">
|
<Get name="HiddenClassMatcher">
|
||||||
<Call name="add"><Arg>-org.slf4j.</Arg></Call>
|
<Call name="add"><Arg>-org.slf4j.</Arg></Call>
|
||||||
<Call name="add"><Arg>-org.eclipse.jetty.logging.</Arg></Call>
|
<Call name="add"><Arg>-org.eclipse.jetty.logging.</Arg></Call>
|
||||||
</Get>
|
</Get>
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-ee</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>jetty-session</artifactId>
|
<artifactId>jetty-session</artifactId>
|
||||||
|
|
|
@ -2,22 +2,21 @@
|
||||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
|
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||||
|
|
||||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||||
<Call class="org.eclipse.jetty.ee10.webapp.WebAppContext" name="addSystemClasses">
|
<Call class="org.eclipse.jetty.ee.WebAppClassLoading" name="addProtectedClasses">
|
||||||
<Arg><Ref refid="Server"/></Arg>
|
<Arg><Ref refid="Environment"/></Arg>
|
||||||
<Arg>
|
<Arg>
|
||||||
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
|
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
|
||||||
<Arg><Property name="jetty.webapp.addSystemClasses"/></Arg>
|
<Arg><Property name="jetty.webapp.addProtectedClasses" deprecated="jetty.webapp.addSystemClasses"/></Arg>
|
||||||
</Call>
|
</Call>
|
||||||
</Arg>
|
</Arg>
|
||||||
</Call>
|
</Call>
|
||||||
|
|
||||||
<Call class="org.eclipse.jetty.ee10.webapp.WebAppContext" name="addServerClasses">
|
<Call class="org.eclipse.jetty.ee.WebAppClassLoading" name="addHiddenClasses">
|
||||||
<Arg><Ref refid="Server"/></Arg>
|
<Arg><Ref refid="Environment"/></Arg>
|
||||||
<Arg>
|
<Arg>
|
||||||
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
|
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
|
||||||
<Arg><Property name="jetty.webapp.addServerClasses"/></Arg>
|
<Arg><Property name="jetty.webapp.addHiddenClasses" deprecated="jetty.webapp.addServerClasses"/></Arg>
|
||||||
</Call>
|
</Call>
|
||||||
</Arg>
|
</Arg>
|
||||||
</Call>
|
</Call>
|
||||||
|
|
||||||
</Configure>
|
</Configure>
|
||||||
|
|
|
@ -9,6 +9,7 @@ This module enables deployment of Java Servlet web applications.
|
||||||
ee10
|
ee10
|
||||||
|
|
||||||
[depend]
|
[depend]
|
||||||
|
ee-webapp
|
||||||
ee10-servlet
|
ee10-servlet
|
||||||
ee10-security
|
ee10-security
|
||||||
|
|
||||||
|
@ -20,9 +21,9 @@ lib/jetty-ee10-webapp-${jetty.version}.jar
|
||||||
|
|
||||||
[ini-template]
|
[ini-template]
|
||||||
# tag::ini-template[]
|
# tag::ini-template[]
|
||||||
## Add to the server wide default jars and packages protected or hidden from webapps.
|
## Add to the environment wide default jars and packages protected or hidden from webapps.
|
||||||
## System classes are protected and cannot be overridden by a webapp.
|
## Protected (aka System) classes cannot be overridden by a webapp.
|
||||||
## Server classes are hidden and cannot be seen by a webapp
|
## Hidden (aka Server) classes cannot be seen by a webapp
|
||||||
## Lists of patterns are comma separated and may be either:
|
## Lists of patterns are comma separated and may be either:
|
||||||
## + a qualified classname e.g. 'com.acme.Foo'
|
## + a qualified classname e.g. 'com.acme.Foo'
|
||||||
## + a package name e.g. 'net.example.'
|
## + a package name e.g. 'net.example.'
|
||||||
|
@ -32,8 +33,8 @@ lib/jetty-ee10-webapp-${jetty.version}.jar
|
||||||
##
|
##
|
||||||
## The +=, operator appends to a CSV list with a comma as needed.
|
## The +=, operator appends to a CSV list with a comma as needed.
|
||||||
##
|
##
|
||||||
#jetty.webapp.addSystemClasses+=,org.example.
|
#jetty.webapp.addProtectedClasses+=,org.example.
|
||||||
#jetty.webapp.addServerClasses+=,org.example.
|
#jetty.webapp.addHiddenClasses+=,org.example.
|
||||||
# end::ini-template[]
|
# end::ini-template[]
|
||||||
|
|
||||||
[ini]
|
[ini]
|
||||||
|
|
|
@ -33,6 +33,7 @@ module org.eclipse.jetty.ee10.webapp
|
||||||
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;
|
||||||
|
requires transitive org.eclipse.jetty.ee;
|
||||||
|
|
||||||
exports org.eclipse.jetty.ee10.webapp;
|
exports org.eclipse.jetty.ee10.webapp;
|
||||||
|
|
||||||
|
|
|
@ -13,804 +13,53 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.ee10.webapp;
|
package org.eclipse.jetty.ee10.webapp;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.AbstractSet;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.util.IncludeExcludeSet;
|
import org.eclipse.jetty.util.IncludeExcludeSet;
|
||||||
import org.eclipse.jetty.util.Index;
|
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
|
||||||
import org.eclipse.jetty.util.TypeUtil;
|
|
||||||
import org.eclipse.jetty.util.URIUtil;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A matcher for classes based on package and/or location and/or module/
|
* @deprecated Use org.eclipse.jetty.util.ClassMatcher
|
||||||
* <p>
|
|
||||||
* Performs pattern matching of a class against a set of pattern entries.
|
|
||||||
* A class pattern is a string of one of the forms:<ul>
|
|
||||||
* <li>'org.package.SomeClass' will match a specific class
|
|
||||||
* <li>'org.package.' will match a specific package hierarchy
|
|
||||||
* <li>'org.package.SomeClass$NestedClass ' will match a nested class exactly otherwise.
|
|
||||||
* Nested classes are matched by their containing class. (eg. org.example.MyClass
|
|
||||||
* matches org.example.MyClass$AnyNestedClass)
|
|
||||||
* <li>'file:///some/location/' - A file system directory from which
|
|
||||||
* the class was loaded
|
|
||||||
* <li>'file:///some/location.jar' - The URI of a jar file from which
|
|
||||||
* the class was loaded
|
|
||||||
* <li>'jrt:/modulename' - A Java9 module name</li>
|
|
||||||
* <li>Any of the above patterns preceded by '-' will exclude rather than include the match.
|
|
||||||
* </ul>
|
|
||||||
* When class is initialized from a classpath pattern string, entries
|
|
||||||
* in this string should be separated by ':' (semicolon) or ',' (comma).
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class ClassMatcher extends AbstractSet<String>
|
@Deprecated(since = "12.0.8", forRemoval = true)
|
||||||
|
public class ClassMatcher extends org.eclipse.jetty.util.ClassMatcher
|
||||||
{
|
{
|
||||||
public static class Entry
|
|
||||||
{
|
|
||||||
private final String _pattern;
|
|
||||||
private final String _name;
|
|
||||||
private final boolean _inclusive;
|
|
||||||
|
|
||||||
protected Entry(String name, boolean inclusive)
|
|
||||||
{
|
|
||||||
_name = name;
|
|
||||||
_inclusive = inclusive;
|
|
||||||
_pattern = inclusive ? _name : ("-" + _name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPattern()
|
|
||||||
{
|
|
||||||
return _pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName()
|
|
||||||
{
|
|
||||||
return _name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return _pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return _pattern.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o)
|
|
||||||
{
|
|
||||||
return (o instanceof Entry) && _pattern.equals(((Entry)o)._pattern);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isInclusive()
|
|
||||||
{
|
|
||||||
return _inclusive;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class PackageEntry extends Entry
|
|
||||||
{
|
|
||||||
protected PackageEntry(String name, boolean inclusive)
|
|
||||||
{
|
|
||||||
super(name, inclusive);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ClassEntry extends Entry
|
|
||||||
{
|
|
||||||
protected ClassEntry(String name, boolean inclusive)
|
|
||||||
{
|
|
||||||
super(name, inclusive);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class LocationEntry extends Entry
|
|
||||||
{
|
|
||||||
private final Path _path;
|
|
||||||
|
|
||||||
protected LocationEntry(String name, boolean inclusive)
|
|
||||||
{
|
|
||||||
super(name, inclusive);
|
|
||||||
URI uri = URI.create(name);
|
|
||||||
if (!uri.isAbsolute() && !"file".equalsIgnoreCase(uri.getScheme()))
|
|
||||||
throw new IllegalArgumentException("Not a valid file URI: " + name);
|
|
||||||
|
|
||||||
_path = Paths.get(uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Path getPath()
|
|
||||||
{
|
|
||||||
return _path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ModuleEntry extends Entry
|
|
||||||
{
|
|
||||||
private final String _module;
|
|
||||||
|
|
||||||
protected ModuleEntry(String name, boolean inclusive)
|
|
||||||
{
|
|
||||||
super(name, inclusive);
|
|
||||||
if (!getName().startsWith("jrt:"))
|
|
||||||
throw new IllegalArgumentException(name);
|
|
||||||
_module = getName().split("/")[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getModule()
|
|
||||||
{
|
|
||||||
return _module;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ByPackage extends AbstractSet<Entry> implements Predicate<String>
|
|
||||||
{
|
|
||||||
private final Index.Mutable<Entry> _entries = new Index.Builder<Entry>()
|
|
||||||
.caseSensitive(true)
|
|
||||||
.mutable()
|
|
||||||
.build();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean test(String name)
|
|
||||||
{
|
|
||||||
return _entries.getBest(name) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<Entry> iterator()
|
|
||||||
{
|
|
||||||
return _entries.keySet().stream().map(_entries::get).iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return _entries.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEmpty()
|
|
||||||
{
|
|
||||||
return _entries.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean add(Entry entry)
|
|
||||||
{
|
|
||||||
String name = entry.getName();
|
|
||||||
if (entry instanceof ClassEntry)
|
|
||||||
name += "$";
|
|
||||||
else if (!(entry instanceof PackageEntry))
|
|
||||||
throw new IllegalArgumentException(entry.toString());
|
|
||||||
else if (".".equals(name))
|
|
||||||
name = "";
|
|
||||||
|
|
||||||
if (_entries.get(name) != null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return _entries.put(name, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean remove(Object entry)
|
|
||||||
{
|
|
||||||
if (!(entry instanceof Entry))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return _entries.remove(((Entry)entry).getName()) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear()
|
|
||||||
{
|
|
||||||
_entries.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ByClass extends HashSet<Entry> implements Predicate<String>
|
|
||||||
{
|
|
||||||
private final Map<String, Entry> _entries = new HashMap<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean test(String name)
|
|
||||||
{
|
|
||||||
return _entries.containsKey(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<Entry> iterator()
|
|
||||||
{
|
|
||||||
return _entries.values().iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return _entries.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean add(Entry entry)
|
|
||||||
{
|
|
||||||
if (!(entry instanceof ClassEntry))
|
|
||||||
throw new IllegalArgumentException(entry.toString());
|
|
||||||
return _entries.put(entry.getName(), entry) == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean remove(Object entry)
|
|
||||||
{
|
|
||||||
if (!(entry instanceof Entry))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return _entries.remove(((Entry)entry).getName()) != null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ByPackageOrName extends AbstractSet<Entry> implements Predicate<String>
|
|
||||||
{
|
|
||||||
private final ByClass _byClass = new ByClass();
|
|
||||||
private final ByPackage _byPackage = new ByPackage();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean test(String name)
|
|
||||||
{
|
|
||||||
return _byPackage.test(name) || _byClass.test(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<Entry> iterator()
|
|
||||||
{
|
|
||||||
// by package contains all entries (classes are also $ packages).
|
|
||||||
return _byPackage.iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return _byPackage.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean add(Entry entry)
|
|
||||||
{
|
|
||||||
if (entry instanceof PackageEntry)
|
|
||||||
return _byPackage.add(entry);
|
|
||||||
|
|
||||||
if (entry instanceof ClassEntry)
|
|
||||||
{
|
|
||||||
// Add class name to packages also as classes act
|
|
||||||
// as packages for nested classes.
|
|
||||||
boolean added = _byPackage.add(entry);
|
|
||||||
added = _byClass.add(entry) || added;
|
|
||||||
return added;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean remove(Object o)
|
|
||||||
{
|
|
||||||
if (!(o instanceof Entry))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
boolean removedPackage = _byPackage.remove(o);
|
|
||||||
boolean removedClass = _byClass.remove(o);
|
|
||||||
|
|
||||||
return removedPackage || removedClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear()
|
|
||||||
{
|
|
||||||
_byPackage.clear();
|
|
||||||
_byClass.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ByLocation extends HashSet<Entry> implements Predicate<URI>
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public boolean test(URI uri)
|
|
||||||
{
|
|
||||||
if ((uri == null) || (!uri.isAbsolute()))
|
|
||||||
return false;
|
|
||||||
if (!uri.getScheme().equals("file"))
|
|
||||||
return false;
|
|
||||||
Path path = Paths.get(uri);
|
|
||||||
|
|
||||||
for (Entry entry : this)
|
|
||||||
{
|
|
||||||
if (!(entry instanceof LocationEntry))
|
|
||||||
throw new IllegalStateException();
|
|
||||||
|
|
||||||
Path entryPath = ((LocationEntry)entry).getPath();
|
|
||||||
|
|
||||||
if (Files.isDirectory(entryPath))
|
|
||||||
{
|
|
||||||
if (path.startsWith(entryPath))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (Files.isSameFile(path, entryPath))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException ignore)
|
|
||||||
{
|
|
||||||
// this means there is a FileSystem issue preventing comparison.
|
|
||||||
// Use old technique
|
|
||||||
if (path.equals(entryPath))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ByModule extends HashSet<Entry> implements Predicate<URI>
|
|
||||||
{
|
|
||||||
private final Index.Mutable<Entry> _entries = new Index.Builder<Entry>()
|
|
||||||
.caseSensitive(true)
|
|
||||||
.mutable()
|
|
||||||
.build();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean test(URI uri)
|
|
||||||
{
|
|
||||||
if ((uri == null) || (!uri.isAbsolute()))
|
|
||||||
return false;
|
|
||||||
if (!uri.getScheme().equalsIgnoreCase("jrt"))
|
|
||||||
return false;
|
|
||||||
String module = uri.getPath();
|
|
||||||
int end = module.indexOf('/', 1);
|
|
||||||
if (end < 1)
|
|
||||||
end = module.length();
|
|
||||||
return _entries.get(module, 1, end - 1) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<Entry> iterator()
|
|
||||||
{
|
|
||||||
return _entries.keySet().stream().map(_entries::get).iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return _entries.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean add(Entry entry)
|
|
||||||
{
|
|
||||||
if (!(entry instanceof ModuleEntry))
|
|
||||||
throw new IllegalArgumentException(entry.toString());
|
|
||||||
String module = ((ModuleEntry)entry).getModule();
|
|
||||||
|
|
||||||
if (_entries.get(module) != null)
|
|
||||||
return false;
|
|
||||||
_entries.put(module, entry);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean remove(Object entry)
|
|
||||||
{
|
|
||||||
if (!(entry instanceof Entry))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return _entries.remove(((Entry)entry).getName()) != null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ByLocationOrModule extends AbstractSet<Entry> implements Predicate<URI>
|
|
||||||
{
|
|
||||||
private final ByLocation _byLocation = new ByLocation();
|
|
||||||
private final ByModule _byModule = new ByModule();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean test(URI name)
|
|
||||||
{
|
|
||||||
if ((name == null) || (!name.isAbsolute()))
|
|
||||||
return false;
|
|
||||||
return _byLocation.test(name) || _byModule.test(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<Entry> iterator()
|
|
||||||
{
|
|
||||||
Set<Entry> entries = new HashSet<>();
|
|
||||||
entries.addAll(_byLocation);
|
|
||||||
entries.addAll(_byModule);
|
|
||||||
return entries.iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return _byLocation.size() + _byModule.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean add(Entry entry)
|
|
||||||
{
|
|
||||||
if (entry instanceof LocationEntry)
|
|
||||||
return _byLocation.add(entry);
|
|
||||||
if (entry instanceof ModuleEntry)
|
|
||||||
return _byModule.add(entry);
|
|
||||||
|
|
||||||
throw new IllegalArgumentException(entry.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean remove(Object o)
|
|
||||||
{
|
|
||||||
if (o instanceof LocationEntry)
|
|
||||||
return _byLocation.remove(o);
|
|
||||||
if (o instanceof ModuleEntry)
|
|
||||||
return _byModule.remove(o);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear()
|
|
||||||
{
|
|
||||||
_byLocation.clear();
|
|
||||||
_byModule.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private final Map<String, Entry> _entries;
|
|
||||||
private final IncludeExcludeSet<Entry, String> _patterns;
|
|
||||||
private final IncludeExcludeSet<Entry, URI> _locations;
|
|
||||||
|
|
||||||
private ClassMatcher(Map<String, Entry> entries, IncludeExcludeSet<Entry, String> patterns, IncludeExcludeSet<Entry, URI> locations)
|
|
||||||
{
|
|
||||||
_entries = entries;
|
|
||||||
_patterns = patterns == null ? new IncludeExcludeSet<>(ByPackageOrName.class) : patterns;
|
|
||||||
_locations = locations == null ? new IncludeExcludeSet<>(ByLocationOrModule.class) : locations;
|
|
||||||
}
|
|
||||||
|
|
||||||
private ClassMatcher(Map<String, Entry> entries)
|
|
||||||
{
|
|
||||||
this(entries, null, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ClassMatcher()
|
public ClassMatcher()
|
||||||
{
|
{
|
||||||
this(new HashMap<>());
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClassMatcher(ClassMatcher patterns)
|
public ClassMatcher(ClassMatcher patterns)
|
||||||
{
|
{
|
||||||
this(new HashMap<>());
|
super(patterns);
|
||||||
if (patterns != null)
|
}
|
||||||
setAll(patterns.getPatterns());
|
|
||||||
|
public ClassMatcher(org.eclipse.jetty.util.ClassMatcher patterns)
|
||||||
|
{
|
||||||
|
super(patterns);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClassMatcher(String... patterns)
|
public ClassMatcher(String... patterns)
|
||||||
{
|
{
|
||||||
this(new HashMap<>());
|
super(patterns);
|
||||||
if (patterns != null && patterns.length > 0)
|
|
||||||
setAll(patterns);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClassMatcher(String pattern)
|
public ClassMatcher(String pattern)
|
||||||
{
|
{
|
||||||
this(new HashMap<>());
|
super(pattern);
|
||||||
add(pattern);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected ClassMatcher(Map<String, Entry> entries, IncludeExcludeSet<Entry, String> patterns, IncludeExcludeSet<Entry, URI> locations)
|
||||||
|
{
|
||||||
|
super(entries, patterns, locations);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public ClassMatcher asImmutable()
|
public ClassMatcher asImmutable()
|
||||||
{
|
{
|
||||||
return new ClassMatcher(Map.copyOf(_entries),
|
return new ClassMatcher(Map.copyOf(_entries),
|
||||||
_patterns.asImmutable(),
|
_patterns.asImmutable(),
|
||||||
_locations.asImmutable());
|
_locations.asImmutable());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean include(String name)
|
|
||||||
{
|
|
||||||
if (name == null)
|
|
||||||
return false;
|
|
||||||
return add(newEntry(name, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean include(String... name)
|
|
||||||
{
|
|
||||||
boolean added = false;
|
|
||||||
for (String n : name)
|
|
||||||
{
|
|
||||||
if (n != null)
|
|
||||||
added = add(newEntry(n, true)) || added;
|
|
||||||
}
|
|
||||||
return added;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean exclude(String name)
|
|
||||||
{
|
|
||||||
if (name == null)
|
|
||||||
return false;
|
|
||||||
return add(newEntry(name, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean exclude(String... name)
|
|
||||||
{
|
|
||||||
boolean added = false;
|
|
||||||
for (String n : name)
|
|
||||||
{
|
|
||||||
if (n != null)
|
|
||||||
added = add(newEntry(n, false)) || added;
|
|
||||||
}
|
|
||||||
return added;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean add(String pattern)
|
|
||||||
{
|
|
||||||
if (pattern == null)
|
|
||||||
return false;
|
|
||||||
return add(newEntry(pattern));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean add(String... pattern)
|
|
||||||
{
|
|
||||||
boolean added = false;
|
|
||||||
for (String p : pattern)
|
|
||||||
{
|
|
||||||
if (p != null)
|
|
||||||
added = add(newEntry(p)) || added;
|
|
||||||
}
|
|
||||||
return added;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean add(Entry entry)
|
|
||||||
{
|
|
||||||
if (_entries.containsKey(entry.getPattern()))
|
|
||||||
return false;
|
|
||||||
_entries.put(entry.getPattern(), entry);
|
|
||||||
|
|
||||||
if (entry instanceof LocationEntry || entry instanceof ModuleEntry)
|
|
||||||
{
|
|
||||||
if (entry.isInclusive())
|
|
||||||
_locations.include(entry);
|
|
||||||
else
|
|
||||||
_locations.exclude(entry);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (entry.isInclusive())
|
|
||||||
_patterns.include(entry);
|
|
||||||
else
|
|
||||||
_patterns.exclude(entry);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Entry newEntry(String pattern)
|
|
||||||
{
|
|
||||||
if (pattern.startsWith("-"))
|
|
||||||
return newEntry(pattern.substring(1), false);
|
|
||||||
return newEntry(pattern, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Entry newEntry(String name, boolean inclusive)
|
|
||||||
{
|
|
||||||
if (name.startsWith("-"))
|
|
||||||
throw new IllegalStateException(name);
|
|
||||||
if (name.startsWith("file:"))
|
|
||||||
return new LocationEntry(name, inclusive);
|
|
||||||
if (name.startsWith("jrt:"))
|
|
||||||
return new ModuleEntry(name, inclusive);
|
|
||||||
if (name.endsWith("."))
|
|
||||||
return new PackageEntry(name, inclusive);
|
|
||||||
return new ClassEntry(name, inclusive);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean remove(Object o)
|
|
||||||
{
|
|
||||||
if (!(o instanceof String pattern))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Entry entry = _entries.remove(pattern);
|
|
||||||
if (entry == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
List<Entry> saved = new ArrayList<>(_entries.values());
|
|
||||||
clear();
|
|
||||||
for (Entry e : saved)
|
|
||||||
{
|
|
||||||
add(e);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear()
|
|
||||||
{
|
|
||||||
_entries.clear();
|
|
||||||
_patterns.clear();
|
|
||||||
_locations.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<String> iterator()
|
|
||||||
{
|
|
||||||
return _entries.keySet().iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return _entries.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the matcher by parsing each classpath pattern in an array
|
|
||||||
*
|
|
||||||
* @param classes array of classpath patterns
|
|
||||||
*/
|
|
||||||
private void setAll(String[] classes)
|
|
||||||
{
|
|
||||||
_entries.clear();
|
|
||||||
addAll(classes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add array of classpath patterns.
|
|
||||||
* @param classes array of classpath patterns
|
|
||||||
*/
|
|
||||||
private void addAll(String[] classes)
|
|
||||||
{
|
|
||||||
if (classes != null)
|
|
||||||
addAll(Arrays.asList(classes));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array of classpath patterns
|
|
||||||
*/
|
|
||||||
public String[] getPatterns()
|
|
||||||
{
|
|
||||||
return toArray(new String[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array of inclusive classpath patterns
|
|
||||||
*/
|
|
||||||
public String[] getInclusions()
|
|
||||||
{
|
|
||||||
return _entries.values().stream().filter(Entry::isInclusive).map(Entry::getName).toArray(String[]::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array of excluded classpath patterns (without '-' prefix)
|
|
||||||
*/
|
|
||||||
public String[] getExclusions()
|
|
||||||
{
|
|
||||||
return _entries.values().stream().filter(e -> !e.isInclusive()).map(Entry::getName).toArray(String[]::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Match the class name against the pattern
|
|
||||||
*
|
|
||||||
* @param name name of the class to match
|
|
||||||
* @return true if class matches the pattern
|
|
||||||
*/
|
|
||||||
public boolean match(String name)
|
|
||||||
{
|
|
||||||
return _patterns.test(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Match the class name against the pattern
|
|
||||||
*
|
|
||||||
* @param clazz A class to try to match
|
|
||||||
* @return true if class matches the pattern
|
|
||||||
*/
|
|
||||||
public boolean match(Class<?> clazz)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return combine(_patterns, clazz.getName(), _locations, () -> TypeUtil.getLocationOfClass(clazz));
|
|
||||||
}
|
|
||||||
catch (Exception ignored)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean match(String name, URL url)
|
|
||||||
{
|
|
||||||
if (url == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Strip class suffix for name matching
|
|
||||||
if (name.endsWith(".class"))
|
|
||||||
name = name.substring(0, name.length() - 6);
|
|
||||||
|
|
||||||
// Treat path elements as packages for name matching
|
|
||||||
name = StringUtil.replace(name, '/', '.');
|
|
||||||
|
|
||||||
return combine(_patterns, name, _locations, () ->
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return URIUtil.unwrapContainer(url.toURI());
|
|
||||||
}
|
|
||||||
catch (URISyntaxException ignored)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Match a class against inclusions and exclusions by name and location.
|
|
||||||
* Name based checks are performed before location checks. For a class to match,
|
|
||||||
* it must not be excluded by either name or location, and must either be explicitly
|
|
||||||
* included, or for there to be no inclusions. In the case where the location
|
|
||||||
* of the class is null, it will match if it is included by name, or
|
|
||||||
* if there are no location exclusions.
|
|
||||||
*
|
|
||||||
* @param names configured inclusions and exclusions by name
|
|
||||||
* @param name the name to check
|
|
||||||
* @param locations configured inclusions and exclusions by location
|
|
||||||
* @param location the location of the class (can be null)
|
|
||||||
* @return true if the class is not excluded but is included, or there are
|
|
||||||
* no inclusions. False otherwise.
|
|
||||||
*/
|
|
||||||
static boolean combine(IncludeExcludeSet<Entry, String> names, String name, IncludeExcludeSet<Entry, URI> locations, Supplier<URI> location)
|
|
||||||
{
|
|
||||||
// check the name set
|
|
||||||
Boolean byName = names.isIncludedAndNotExcluded(name);
|
|
||||||
|
|
||||||
// If we excluded by name, then no match
|
|
||||||
if (Boolean.FALSE == byName)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// check the location set
|
|
||||||
URI uri = location.get();
|
|
||||||
Boolean byLocation = uri == null ? null : locations.isIncludedAndNotExcluded(uri);
|
|
||||||
|
|
||||||
// If we excluded by location or couldn't check location exclusion, then no match
|
|
||||||
if (Boolean.FALSE == byLocation || (locations.hasExcludes() && uri == null))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// If there are includes, then we must be included to match.
|
|
||||||
if (names.hasIncludes() || locations.hasIncludes())
|
|
||||||
return byName == Boolean.TRUE || byLocation == Boolean.TRUE;
|
|
||||||
|
|
||||||
// Otherwise there are no includes and it was not excluded, so match
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,8 +60,8 @@ import org.slf4j.LoggerFactory;
|
||||||
* parent loader. Java2 compliant loading, where the parent loader
|
* parent loader. Java2 compliant loading, where the parent loader
|
||||||
* always has priority, can be selected with the
|
* always has priority, can be selected with the
|
||||||
* {@link WebAppContext#setParentLoaderPriority(boolean)}
|
* {@link WebAppContext#setParentLoaderPriority(boolean)}
|
||||||
* method and influenced with {@link WebAppContext#isServerClass(Class)} and
|
* method and influenced with {@link WebAppContext#isHiddenClass(Class)} and
|
||||||
* {@link WebAppContext#isSystemClass(Class)}.
|
* {@link WebAppContext#isProtectedClass(Class)}.
|
||||||
* <p>
|
* <p>
|
||||||
* If no parent class loader is provided, then the current thread
|
* If no parent class loader is provided, then the current thread
|
||||||
* context classloader will be used. If that is null then the
|
* context classloader will be used. If that is null then the
|
||||||
|
@ -115,9 +115,9 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
||||||
|
|
||||||
List<Resource> getExtraClasspath();
|
List<Resource> getExtraClasspath();
|
||||||
|
|
||||||
boolean isServerResource(String name, URL parentUrl);
|
boolean isHiddenResource(String name, URL parentUrl);
|
||||||
|
|
||||||
boolean isSystemResource(String name, URL webappUrl);
|
boolean isProtectedResource(String name, URL webappUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -302,7 +302,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
||||||
while (urls != null && urls.hasMoreElements())
|
while (urls != null && urls.hasMoreElements())
|
||||||
{
|
{
|
||||||
URL url = urls.nextElement();
|
URL url = urls.nextElement();
|
||||||
if (Boolean.TRUE.equals(__loadServerClasses.get()) || !_context.isServerResource(name, url))
|
if (Boolean.TRUE.equals(__loadServerClasses.get()) || !_context.isHiddenResource(name, url))
|
||||||
fromParent.add(url);
|
fromParent.add(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,7 +310,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
||||||
while (urls != null && urls.hasMoreElements())
|
while (urls != null && urls.hasMoreElements())
|
||||||
{
|
{
|
||||||
URL url = urls.nextElement();
|
URL url = urls.nextElement();
|
||||||
if (!_context.isSystemResource(name, url) || fromParent.isEmpty())
|
if (!_context.isProtectedResource(name, url) || fromParent.isEmpty())
|
||||||
fromWebapp.add(url);
|
fromWebapp.add(url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,7 +351,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
||||||
// return if we have a url the webapp is allowed to see
|
// return if we have a url the webapp is allowed to see
|
||||||
if (parentUrl != null &&
|
if (parentUrl != null &&
|
||||||
(Boolean.TRUE.equals(__loadServerClasses.get()) ||
|
(Boolean.TRUE.equals(__loadServerClasses.get()) ||
|
||||||
!_context.isServerResource(name, parentUrl)))
|
!_context.isHiddenResource(name, parentUrl)))
|
||||||
resource = parentUrl;
|
resource = parentUrl;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -370,7 +370,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
||||||
{
|
{
|
||||||
URL webappUrl = this.findResource(name);
|
URL webappUrl = this.findResource(name);
|
||||||
|
|
||||||
if (webappUrl != null && !_context.isSystemResource(name, webappUrl))
|
if (webappUrl != null && !_context.isProtectedResource(name, webappUrl))
|
||||||
resource = webappUrl;
|
resource = webappUrl;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -379,7 +379,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
||||||
URL parentUrl = _parent.getResource(name);
|
URL parentUrl = _parent.getResource(name);
|
||||||
if (parentUrl != null &&
|
if (parentUrl != null &&
|
||||||
(Boolean.TRUE.equals(__loadServerClasses.get()) ||
|
(Boolean.TRUE.equals(__loadServerClasses.get()) ||
|
||||||
!_context.isServerResource(name, parentUrl)))
|
!_context.isHiddenResource(name, parentUrl)))
|
||||||
resource = parentUrl;
|
resource = parentUrl;
|
||||||
// We couldn't find a parent resource, so OK to return a webapp one if it exists
|
// We couldn't find a parent resource, so OK to return a webapp one if it exists
|
||||||
// and we just couldn't see it before
|
// and we just couldn't see it before
|
||||||
|
@ -425,7 +425,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
||||||
throw new ClassNotFoundException("Bad ClassLoader: returned null for loadClass(" + name + ")");
|
throw new ClassNotFoundException("Bad ClassLoader: returned null for loadClass(" + name + ")");
|
||||||
|
|
||||||
// If the webapp is allowed to see this class
|
// If the webapp is allowed to see this class
|
||||||
if (Boolean.TRUE.equals(__loadServerClasses.get()) || !_context.isServerClass(parentClass))
|
if (Boolean.TRUE.equals(__loadServerClasses.get()) || !_context.isHiddenClass(parentClass))
|
||||||
{
|
{
|
||||||
return parentClass;
|
return parentClass;
|
||||||
}
|
}
|
||||||
|
@ -473,7 +473,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
||||||
{
|
{
|
||||||
parentClass = _parent.loadClass(name);
|
parentClass = _parent.loadClass(name);
|
||||||
// If the webapp is allowed to see this class
|
// If the webapp is allowed to see this class
|
||||||
if (Boolean.TRUE.equals(__loadServerClasses.get()) || !_context.isServerClass(parentClass))
|
if (Boolean.TRUE.equals(__loadServerClasses.get()) || !_context.isHiddenClass(parentClass))
|
||||||
{
|
{
|
||||||
return parentClass;
|
return parentClass;
|
||||||
}
|
}
|
||||||
|
@ -524,7 +524,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
||||||
String path = TypeUtil.toClassReference(name);
|
String path = TypeUtil.toClassReference(name);
|
||||||
URL webappUrl = findResource(path);
|
URL webappUrl = findResource(path);
|
||||||
|
|
||||||
if (webappUrl != null && (!checkSystemResource || !_context.isSystemResource(name, webappUrl)))
|
if (webappUrl != null && (!checkSystemResource || !_context.isProtectedResource(name, webappUrl)))
|
||||||
{
|
{
|
||||||
|
|
||||||
webappClass = this.foundClass(name, webappUrl);
|
webappClass = this.foundClass(name, webappUrl);
|
||||||
|
@ -605,14 +605,14 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSystemClass(Class<?> clazz)
|
public boolean isProtectedClass(Class<?> clazz)
|
||||||
{
|
{
|
||||||
return _context.isSystemClass(clazz);
|
return _context.isProtectedClass(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isServerClass(Class<?> clazz)
|
public boolean isHiddenClass(Class<?> clazz)
|
||||||
{
|
{
|
||||||
return _context.isServerClass(clazz);
|
return _context.isHiddenClass(clazz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ 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.WebAppClassLoading;
|
||||||
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;
|
||||||
|
@ -49,6 +50,7 @@ import org.eclipse.jetty.server.Connector;
|
||||||
import org.eclipse.jetty.server.Deployable;
|
import org.eclipse.jetty.server.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.ClassMatcher;
|
||||||
import org.eclipse.jetty.util.ExceptionUtil;
|
import org.eclipse.jetty.util.ExceptionUtil;
|
||||||
import org.eclipse.jetty.util.IO;
|
import org.eclipse.jetty.util.IO;
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
|
@ -80,32 +82,35 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
||||||
static final Logger LOG = LoggerFactory.getLogger(WebAppContext.class);
|
static final Logger LOG = LoggerFactory.getLogger(WebAppContext.class);
|
||||||
|
|
||||||
public static final String WEB_DEFAULTS_XML = "org/eclipse/jetty/ee10/webapp/webdefault-ee10.xml";
|
public static final String WEB_DEFAULTS_XML = "org/eclipse/jetty/ee10/webapp/webdefault-ee10.xml";
|
||||||
public static final String SERVER_SYS_CLASSES = "org.eclipse.jetty.webapp.systemClasses";
|
/**
|
||||||
public static final String SERVER_SRV_CLASSES = "org.eclipse.jetty.webapp.serverClasses";
|
* @deprecated use {@link WebAppClassLoading#PROTECTED_CLASSES_ATTRIBUTE} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated(forRemoval = true, since = "12.0.9")
|
||||||
|
public static final String SERVER_SYS_CLASSES = WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE;
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link WebAppClassLoading#HIDDEN_CLASSES_ATTRIBUTE} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated(forRemoval = true, since = "12.0.9")
|
||||||
|
public static final String SERVER_SRV_CLASSES = WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE;
|
||||||
|
|
||||||
private static String[] __dftProtectedTargets = {"/WEB-INF", "/META-INF"};
|
private static final String[] __dftProtectedTargets = {"/WEB-INF", "/META-INF"};
|
||||||
|
|
||||||
// System classes are classes that cannot be replaced by
|
/**
|
||||||
// the web application, and they are *always* loaded via
|
* @deprecated use {@link WebAppClassLoading#DEFAULT_PROTECTED_CLASSES}
|
||||||
// system classloader.
|
*/
|
||||||
public static final ClassMatcher __dftSystemClasses = new ClassMatcher(
|
@Deprecated (forRemoval = true, since = "12.0.9")
|
||||||
"java.", // Java SE classes (per servlet spec v2.5 / SRV.9.7.2)
|
public static final org.eclipse.jetty.ee10.webapp.ClassMatcher __dftSystemClasses =
|
||||||
"javax.", // Java SE classes (per servlet spec v2.5 / SRV.9.7.2)
|
new org.eclipse.jetty.ee10.webapp.ClassMatcher(WebAppClassLoading.DEFAULT_PROTECTED_CLASSES);
|
||||||
"jakarta.", // Jakarta classes (per servlet spec v5.0 / Section 15.2.1)
|
|
||||||
"org.xml.", // javax.xml
|
|
||||||
"org.w3c." // javax.xml
|
|
||||||
);
|
|
||||||
|
|
||||||
// Server classes are classes that are hidden from being
|
/**
|
||||||
// loaded by the web application using system classloader,
|
* @deprecated use {@link WebAppClassLoading#DEFAULT_HIDDEN_CLASSES}
|
||||||
// so if web application needs to load any of such classes,
|
*/
|
||||||
// it has to include them in its distribution.
|
@Deprecated (forRemoval = true, since = "12.0.9")
|
||||||
public static final ClassMatcher __dftServerClasses = new ClassMatcher(
|
public static final org.eclipse.jetty.ee10.webapp.ClassMatcher __dftServerClasses =
|
||||||
"org.eclipse.jetty." // hide jetty classes
|
new org.eclipse.jetty.ee10.webapp.ClassMatcher(WebAppClassLoading.DEFAULT_HIDDEN_CLASSES);
|
||||||
);
|
|
||||||
|
|
||||||
private final ClassMatcher _systemClasses = new ClassMatcher(__dftSystemClasses);
|
private final ClassMatcher _protectedClasses = new ClassMatcher(WebAppClassLoading.getProtectedClasses(ServletContextHandler.ENVIRONMENT));
|
||||||
private final ClassMatcher _serverClasses = new ClassMatcher(__dftServerClasses);
|
private final ClassMatcher _hiddenClasses = new ClassMatcher(WebAppClassLoading.getHiddenClasses(ServletContextHandler.ENVIRONMENT));
|
||||||
|
|
||||||
private Configurations _configurations;
|
private Configurations _configurations;
|
||||||
private String _defaultsDescriptor = WEB_DEFAULTS_XML;
|
private String _defaultsDescriptor = WEB_DEFAULTS_XML;
|
||||||
|
@ -420,7 +425,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
||||||
// Add the known server class inclusions for all known configurations
|
// Add the known server class inclusions for all known configurations
|
||||||
for (Configuration configuration : Configurations.getKnown())
|
for (Configuration configuration : Configurations.getKnown())
|
||||||
{
|
{
|
||||||
_serverClasses.include(configuration.getServerClasses().getInclusions());
|
_hiddenClasses.include(configuration.getServerClasses().getInclusions());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup Configuration classes for this webapp!
|
// Setup Configuration classes for this webapp!
|
||||||
|
@ -428,8 +433,8 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
||||||
_configurations.sort();
|
_configurations.sort();
|
||||||
for (Configuration configuration : _configurations)
|
for (Configuration configuration : _configurations)
|
||||||
{
|
{
|
||||||
_systemClasses.add(configuration.getSystemClasses().getPatterns());
|
_protectedClasses.add(configuration.getSystemClasses().getPatterns());
|
||||||
_serverClasses.exclude(configuration.getServerClasses().getExclusions());
|
_hiddenClasses.exclude(configuration.getServerClasses().getExclusions());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Configure classloader
|
// Configure classloader
|
||||||
|
@ -484,7 +489,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
||||||
protected void doStart() throws Exception
|
protected void doStart() throws Exception
|
||||||
{
|
{
|
||||||
ClassLoader old = Thread.currentThread().getContextClassLoader();
|
ClassLoader old = Thread.currentThread().getContextClassLoader();
|
||||||
Thread.currentThread().setContextClassLoader(__environment.getClassLoader());
|
Thread.currentThread().setContextClassLoader(ServletContextHandler.ENVIRONMENT.getClassLoader());
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_metadata.setAllowDuplicateFragmentNames(isAllowDuplicateFragmentNames());
|
_metadata.setAllowDuplicateFragmentNames(isAllowDuplicateFragmentNames());
|
||||||
|
@ -615,107 +620,217 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the server classes patterns.
|
* Set the hidden (aka server) classes patterns.
|
||||||
* <p>
|
* <p>
|
||||||
* Server classes/packages are classes used to implement the server and are hidden
|
* These classes/packages are used to implement the server and are hiddenClasses
|
||||||
* from the context. If the context needs to load these classes, it must have its
|
* from the context. If the context needs to load these classes, it must have its
|
||||||
* own copy of them in WEB-INF/lib or WEB-INF/classes.
|
* own copy of them in WEB-INF/lib or WEB-INF/classes.
|
||||||
*
|
*
|
||||||
* @param serverClasses the server classes pattern
|
* @param hiddenClasses the server classes pattern
|
||||||
*/
|
*/
|
||||||
public void setServerClassMatcher(ClassMatcher serverClasses)
|
public void setHiddenClassMatcher(ClassMatcher hiddenClasses)
|
||||||
{
|
{
|
||||||
_serverClasses.clear();
|
_hiddenClasses.clear();
|
||||||
_serverClasses.add(serverClasses.getPatterns());
|
_hiddenClasses.add(hiddenClasses.getPatterns());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the system classes patterns.
|
* Set the protected (aka system) classes patterns.
|
||||||
* <p>
|
* <p>
|
||||||
* System classes/packages are classes provided by the JVM and that
|
* These classes/packages are provided by the JVM and
|
||||||
* cannot be replaced by classes of the same name from WEB-INF,
|
* cannot be replaced by classes of the same name from WEB-INF,
|
||||||
* regardless of the value of {@link #setParentLoaderPriority(boolean)}.
|
* regardless of the value of {@link #setParentLoaderPriority(boolean)}.
|
||||||
*
|
*
|
||||||
* @param systemClasses the system classes pattern
|
* @param protectedClasses the system classes pattern
|
||||||
*/
|
*/
|
||||||
public void setSystemClassMatcher(ClassMatcher systemClasses)
|
public void setProtectedClassMatcher(ClassMatcher protectedClasses)
|
||||||
{
|
{
|
||||||
_systemClasses.clear();
|
_protectedClasses.clear();
|
||||||
_systemClasses.add(systemClasses.getPatterns());
|
_protectedClasses.add(protectedClasses.getPatterns());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a ClassMatcher for server classes by combining with
|
* Add a ClassMatcher for hidden (server) classes by combining with
|
||||||
* any existing matcher.
|
* any existing matcher.
|
||||||
*
|
*
|
||||||
* @param serverClasses The class matcher of patterns to add to the server ClassMatcher
|
* @param hiddenClasses The class matcher of patterns to add to the server ClassMatcher
|
||||||
*/
|
*/
|
||||||
public void addServerClassMatcher(ClassMatcher serverClasses)
|
public void addHiddenClassMatcher(ClassMatcher hiddenClasses)
|
||||||
{
|
{
|
||||||
_serverClasses.add(serverClasses.getPatterns());
|
_hiddenClasses.add(hiddenClasses.getPatterns());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a ClassMatcher for system classes by combining with
|
* Add a ClassMatcher for protected (system) classes by combining with
|
||||||
* any existing matcher.
|
* any existing matcher.
|
||||||
*
|
*
|
||||||
* @param systemClasses The class matcher of patterns to add to the system ClassMatcher
|
* @param protectedClasses The class matcher of patterns to add to the system ClassMatcher
|
||||||
*/
|
*/
|
||||||
public void addSystemClassMatcher(ClassMatcher systemClasses)
|
public void addProtectedClassMatcher(ClassMatcher protectedClasses)
|
||||||
{
|
{
|
||||||
_systemClasses.add(systemClasses.getPatterns());
|
_protectedClasses.add(protectedClasses.getPatterns());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The ClassMatcher used to match System (protected) classes
|
* @return The ClassMatcher used to match System (protected) classes
|
||||||
*/
|
*/
|
||||||
public ClassMatcher getSystemClassMatcher()
|
public ClassMatcher getProtectedClassMatcher()
|
||||||
{
|
{
|
||||||
return _systemClasses;
|
return _protectedClasses;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return The ClassMatcher used to match Server (hidden) classes
|
* @return The ClassMatcher used to match Server (hiddenClasses) classes
|
||||||
*/
|
*/
|
||||||
public ClassMatcher getServerClassMatcher()
|
public ClassMatcher getHiddenClassMatcher()
|
||||||
{
|
{
|
||||||
return _serverClasses;
|
return _hiddenClasses;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ManagedAttribute(value = "classes and packages protected by context classloader", readonly = true)
|
@ManagedAttribute(value = "classes and packages protected by context classloader", readonly = true)
|
||||||
|
public String[] getProtectedClasses()
|
||||||
|
{
|
||||||
|
return _protectedClasses.getPatterns();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ManagedAttribute(value = "classes and packages hiddenClasses by the context classloader", readonly = true)
|
||||||
|
public String[] getHiddenClasses()
|
||||||
|
{
|
||||||
|
return _hiddenClasses.getPatterns();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isHiddenClass(Class<?> clazz)
|
||||||
|
{
|
||||||
|
return _hiddenClasses.match(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isProtectedClass(Class<?> clazz)
|
||||||
|
{
|
||||||
|
return _protectedClasses.match(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isHiddenResource(String name, URL url)
|
||||||
|
{
|
||||||
|
return _hiddenClasses.match(name, url);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isProtectedResource(String name, URL url)
|
||||||
|
{
|
||||||
|
return _protectedClasses.match(name, url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #setHiddenClassMatcher(ClassMatcher)}
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "12.0.8", forRemoval = true)
|
||||||
|
public void setServerClassMatcher(ClassMatcher serverClasses)
|
||||||
|
{
|
||||||
|
_hiddenClasses.clear();
|
||||||
|
_hiddenClasses.add(serverClasses.getPatterns());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #setProtectedClassMatcher(ClassMatcher)}
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "12.0.8", forRemoval = true)
|
||||||
|
public void setSystemClassMatcher(ClassMatcher systemClasses)
|
||||||
|
{
|
||||||
|
_protectedClasses.clear();
|
||||||
|
_protectedClasses.add(systemClasses.getPatterns());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #addHiddenClassMatcher(ClassMatcher)}
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "12.0.8", forRemoval = true)
|
||||||
|
public void addServerClassMatcher(ClassMatcher serverClasses)
|
||||||
|
{
|
||||||
|
_hiddenClasses.add(serverClasses.getPatterns());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #addProtectedClassMatcher(ClassMatcher)}
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "12.0.8", forRemoval = true)
|
||||||
|
public void addSystemClassMatcher(ClassMatcher systemClasses)
|
||||||
|
{
|
||||||
|
_protectedClasses.add(systemClasses.getPatterns());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #getProtectedClassMatcher()}
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "12.0.8", forRemoval = true)
|
||||||
|
public ClassMatcher getSystemClassMatcher()
|
||||||
|
{
|
||||||
|
return _protectedClasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #getHiddenClassMatcher()}
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "12.0.8", forRemoval = true)
|
||||||
|
public ClassMatcher getServerClassMatcher()
|
||||||
|
{
|
||||||
|
return _hiddenClasses;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link #getProtectedClasses()}
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "12.0.8", forRemoval = true)
|
||||||
public String[] getSystemClasses()
|
public String[] getSystemClasses()
|
||||||
{
|
{
|
||||||
return _systemClasses.getPatterns();
|
return _protectedClasses.getPatterns();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ManagedAttribute(value = "classes and packages hidden by the context classloader", readonly = true)
|
/**
|
||||||
|
* @deprecated use {@link #getHiddenClasses()}
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "12.0.8", forRemoval = true)
|
||||||
public String[] getServerClasses()
|
public String[] getServerClasses()
|
||||||
{
|
{
|
||||||
return _serverClasses.getPatterns();
|
return _hiddenClasses.getPatterns();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
|
* @deprecated use {@link #isHiddenClass(Class)}
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "12.0.8", forRemoval = true)
|
||||||
public boolean isServerClass(Class<?> clazz)
|
public boolean isServerClass(Class<?> clazz)
|
||||||
{
|
{
|
||||||
return _serverClasses.match(clazz);
|
return _hiddenClasses.match(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
|
* @deprecated use {@link #isProtectedClass(Class)}
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "12.0.8", forRemoval = true)
|
||||||
public boolean isSystemClass(Class<?> clazz)
|
public boolean isSystemClass(Class<?> clazz)
|
||||||
{
|
{
|
||||||
return _systemClasses.match(clazz);
|
return _protectedClasses.match(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
|
* @deprecated use {@link #isHiddenResource(String, URL)}
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "12.0.8", forRemoval = true)
|
||||||
public boolean isServerResource(String name, URL url)
|
public boolean isServerResource(String name, URL url)
|
||||||
{
|
{
|
||||||
return _serverClasses.match(name, url);
|
return _hiddenClasses.match(name, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
|
* @deprecated use {@link #isProtectedResource(String, URL)}
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "12.0.8", forRemoval = true)
|
||||||
public boolean isSystemResource(String name, URL url)
|
public boolean isSystemResource(String name, URL url)
|
||||||
{
|
{
|
||||||
return _systemClasses.match(name, url);
|
return _protectedClasses.match(name, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -724,23 +839,8 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
||||||
super.setServer(server);
|
super.setServer(server);
|
||||||
if (server != null)
|
if (server != null)
|
||||||
{
|
{
|
||||||
if (__dftSystemClasses.equals(_systemClasses))
|
_protectedClasses.add(WebAppClassLoading.getProtectedClasses(server).getPatterns());
|
||||||
{
|
_hiddenClasses.add(WebAppClassLoading.getHiddenClasses(server).getPatterns());
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -863,16 +963,16 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
||||||
public void dump(Appendable out, String indent) throws IOException
|
public void dump(Appendable out, String indent) throws IOException
|
||||||
{
|
{
|
||||||
List<String> systemClasses = null;
|
List<String> systemClasses = null;
|
||||||
if (_systemClasses != null)
|
if (_protectedClasses != null)
|
||||||
{
|
{
|
||||||
systemClasses = new ArrayList<>(_systemClasses);
|
systemClasses = new ArrayList<>(_protectedClasses);
|
||||||
Collections.sort(systemClasses);
|
Collections.sort(systemClasses);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> serverClasses = null;
|
List<String> serverClasses = null;
|
||||||
if (_serverClasses != null)
|
if (_hiddenClasses != null)
|
||||||
{
|
{
|
||||||
serverClasses = new ArrayList<>(_serverClasses);
|
serverClasses = new ArrayList<>(_hiddenClasses);
|
||||||
Collections.sort(serverClasses);
|
Collections.sort(serverClasses);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1411,38 +1511,31 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
||||||
return _metadata;
|
return _metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addServerClasses(Server server, String... pattern)
|
/**
|
||||||
|
* Add a Server Class pattern to use for all ee9 WebAppContexts.
|
||||||
|
* @param server The {@link Server} instance to add classes to
|
||||||
|
* @param patterns the patterns to use
|
||||||
|
* @see #getHiddenClassMatcher()
|
||||||
|
* @see #getHiddenClasses()
|
||||||
|
* @deprecated use {@link WebAppClassLoading#addProtectedClasses(Server, String...)}
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "12.0.8", forRemoval = true)
|
||||||
|
public static void addServerClasses(Server server, String... patterns)
|
||||||
{
|
{
|
||||||
addClasses(__dftServerClasses, SERVER_SRV_CLASSES, server, pattern);
|
WebAppClassLoading.addHiddenClasses(server, patterns);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addSystemClasses(Server server, String... pattern)
|
/**
|
||||||
|
* Add a System Class pattern to use for all ee9 WebAppContexts.
|
||||||
|
* @param server The {@link Server} instance to add classes to
|
||||||
|
* @param patterns the patterns to use
|
||||||
|
* @see #getProtectedClassMatcher()
|
||||||
|
* @see #getProtectedClasses()
|
||||||
|
* @deprecated use {@link WebAppClassLoading#addHiddenClasses(Server, String...)}
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "12.0.8", forRemoval = true)
|
||||||
|
public static void addSystemClasses(Server server, String... patterns)
|
||||||
{
|
{
|
||||||
addClasses(__dftSystemClasses, SERVER_SYS_CLASSES, server, pattern);
|
WebAppClassLoading.addProtectedClasses(server, patterns);
|
||||||
}
|
|
||||||
|
|
||||||
private static void addClasses(ClassMatcher matcher, String attribute, Server server, 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);
|
|
||||||
if (o instanceof ClassMatcher)
|
|
||||||
{
|
|
||||||
((ClassMatcher)o).add(pattern);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] classes;
|
|
||||||
if (o instanceof String[])
|
|
||||||
classes = (String[])o;
|
|
||||||
else
|
|
||||||
classes = matcher.getPatterns();
|
|
||||||
int l = classes.length;
|
|
||||||
classes = Arrays.copyOf(classes, l + pattern.length);
|
|
||||||
System.arraycopy(pattern, 0, classes, l, pattern.length);
|
|
||||||
server.setAttribute(attribute, classes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -95,7 +95,7 @@ public class WebDescriptor extends Descriptor
|
||||||
public WebDescriptorParser(boolean validating) throws IOException
|
public WebDescriptorParser(boolean validating) throws IOException
|
||||||
{
|
{
|
||||||
super(validating);
|
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);
|
URL url = WebDescriptor.class.getResource(catalogName);
|
||||||
if (url == null)
|
if (url == null)
|
||||||
throw new IllegalStateException("Catalog not found: %s/%s".formatted(WebDescriptor.class.getPackageName(), catalogName));
|
throw new IllegalStateException("Catalog not found: %s/%s".formatted(WebDescriptor.class.getPackageName(), catalogName));
|
||||||
|
|
|
@ -26,9 +26,9 @@ import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||||
|
import org.eclipse.jetty.util.ClassMatcher;
|
||||||
import org.eclipse.jetty.util.IO;
|
import org.eclipse.jetty.util.IO;
|
||||||
import org.eclipse.jetty.util.component.LifeCycle;
|
import org.eclipse.jetty.util.component.LifeCycle;
|
||||||
import org.eclipse.jetty.util.resource.FileSystemPool;
|
|
||||||
import org.eclipse.jetty.util.resource.Resource;
|
import org.eclipse.jetty.util.resource.Resource;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
@ -37,7 +37,6 @@ import org.junit.jupiter.api.Test;
|
||||||
import static org.eclipse.jetty.toolchain.test.ExtraMatchers.ordered;
|
import static org.eclipse.jetty.toolchain.test.ExtraMatchers.ordered;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.contains;
|
import static org.hamcrest.Matchers.contains;
|
||||||
import static org.hamcrest.Matchers.empty;
|
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
import static org.hamcrest.Matchers.nullValue;
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
|
@ -211,11 +210,11 @@ public class WebAppClassLoaderTest
|
||||||
@Test
|
@Test
|
||||||
public void testExposedClassDeprecated() throws Exception
|
public void testExposedClassDeprecated() throws Exception
|
||||||
{
|
{
|
||||||
String[] oldSC = _context.getServerClasses();
|
String[] oldSC = _context.getHiddenClasses();
|
||||||
String[] newSC = new String[oldSC.length + 1];
|
String[] newSC = new String[oldSC.length + 1];
|
||||||
newSC[0] = "-org.eclipse.jetty.ee10.webapp.Configuration";
|
newSC[0] = "-org.eclipse.jetty.ee10.webapp.Configuration";
|
||||||
System.arraycopy(oldSC, 0, newSC, 1, oldSC.length);
|
System.arraycopy(oldSC, 0, newSC, 1, oldSC.length);
|
||||||
_context.setServerClassMatcher(new ClassMatcher(newSC));
|
_context.setHiddenClassMatcher(new ClassMatcher(newSC));
|
||||||
|
|
||||||
assertCanLoadClass("org.acme.webapp.ClassInJarA");
|
assertCanLoadClass("org.acme.webapp.ClassInJarA");
|
||||||
assertCanLoadClass("org.acme.webapp.ClassInJarB");
|
assertCanLoadClass("org.acme.webapp.ClassInJarB");
|
||||||
|
@ -228,7 +227,7 @@ public class WebAppClassLoaderTest
|
||||||
@Test
|
@Test
|
||||||
public void testExposedClass() throws Exception
|
public void testExposedClass() throws Exception
|
||||||
{
|
{
|
||||||
_context.getServerClassMatcher().exclude("org.eclipse.jetty.ee10.webapp.Configuration");
|
_context.getHiddenClassMatcher().exclude("org.eclipse.jetty.ee10.webapp.Configuration");
|
||||||
|
|
||||||
assertCanLoadClass("org.acme.webapp.ClassInJarA");
|
assertCanLoadClass("org.acme.webapp.ClassInJarA");
|
||||||
assertCanLoadClass("org.acme.webapp.ClassInJarB");
|
assertCanLoadClass("org.acme.webapp.ClassInJarB");
|
||||||
|
@ -241,18 +240,18 @@ public class WebAppClassLoaderTest
|
||||||
@Test
|
@Test
|
||||||
public void testSystemServerClassDeprecated() throws Exception
|
public void testSystemServerClassDeprecated() throws Exception
|
||||||
{
|
{
|
||||||
String[] oldServC = _context.getServerClasses();
|
String[] oldServC = _context.getHiddenClasses();
|
||||||
String[] newServC = new String[oldServC.length + 1];
|
String[] newServC = new String[oldServC.length + 1];
|
||||||
newServC[0] = "org.eclipse.jetty.ee10.webapp.Configuration";
|
newServC[0] = "org.eclipse.jetty.ee10.webapp.Configuration";
|
||||||
System.arraycopy(oldServC, 0, newServC, 1, oldServC.length);
|
System.arraycopy(oldServC, 0, newServC, 1, oldServC.length);
|
||||||
|
|
||||||
_context.setServerClassMatcher(new ClassMatcher(newServC));
|
_context.setHiddenClassMatcher(new ClassMatcher(newServC));
|
||||||
|
|
||||||
String[] oldSysC = _context.getSystemClasses();
|
String[] oldSysC = _context.getProtectedClasses();
|
||||||
String[] newSysC = new String[oldSysC.length + 1];
|
String[] newSysC = new String[oldSysC.length + 1];
|
||||||
newSysC[0] = "org.eclipse.jetty.ee10.webapp.";
|
newSysC[0] = "org.eclipse.jetty.ee10.webapp.";
|
||||||
System.arraycopy(oldSysC, 0, newSysC, 1, oldSysC.length);
|
System.arraycopy(oldSysC, 0, newSysC, 1, oldSysC.length);
|
||||||
_context.setSystemClassMatcher(new ClassMatcher(newSysC));
|
_context.setProtectedClassMatcher(new ClassMatcher(newSysC));
|
||||||
|
|
||||||
assertCanLoadClass("org.acme.webapp.ClassInJarA");
|
assertCanLoadClass("org.acme.webapp.ClassInJarA");
|
||||||
assertCanLoadClass("org.acme.webapp.ClassInJarB");
|
assertCanLoadClass("org.acme.webapp.ClassInJarB");
|
||||||
|
@ -260,28 +259,28 @@ public class WebAppClassLoaderTest
|
||||||
assertCantLoadClass("org.eclipse.jetty.ee10.webapp.Configuration");
|
assertCantLoadClass("org.eclipse.jetty.ee10.webapp.Configuration");
|
||||||
assertCantLoadClass("org.eclipse.jetty.ee10.webapp.JarScanner");
|
assertCantLoadClass("org.eclipse.jetty.ee10.webapp.JarScanner");
|
||||||
|
|
||||||
oldSysC = _context.getSystemClasses();
|
oldSysC = _context.getProtectedClasses();
|
||||||
newSysC = new String[oldSysC.length + 1];
|
newSysC = new String[oldSysC.length + 1];
|
||||||
newSysC[0] = "org.acme.webapp.ClassInJarA";
|
newSysC[0] = "org.acme.webapp.ClassInJarA";
|
||||||
System.arraycopy(oldSysC, 0, newSysC, 1, oldSysC.length);
|
System.arraycopy(oldSysC, 0, newSysC, 1, oldSysC.length);
|
||||||
_context.setSystemClassMatcher(new ClassMatcher(newSysC));
|
_context.setProtectedClassMatcher(new ClassMatcher(newSysC));
|
||||||
|
|
||||||
assertCanLoadResource("org/acme/webapp/ClassInJarA.class");
|
assertCanLoadResource("org/acme/webapp/ClassInJarA.class");
|
||||||
_context.setSystemClassMatcher(new ClassMatcher(oldSysC));
|
_context.setProtectedClassMatcher(new ClassMatcher(oldSysC));
|
||||||
|
|
||||||
oldServC = _context.getServerClasses();
|
oldServC = _context.getHiddenClasses();
|
||||||
newServC = new String[oldServC.length + 1];
|
newServC = new String[oldServC.length + 1];
|
||||||
newServC[0] = "org.acme.webapp.ClassInJarA";
|
newServC[0] = "org.acme.webapp.ClassInJarA";
|
||||||
System.arraycopy(oldServC, 0, newServC, 1, oldServC.length);
|
System.arraycopy(oldServC, 0, newServC, 1, oldServC.length);
|
||||||
_context.setServerClassMatcher(new ClassMatcher(newServC));
|
_context.setHiddenClassMatcher(new ClassMatcher(newServC));
|
||||||
assertCanLoadResource("org/acme/webapp/ClassInJarA.class");
|
assertCanLoadResource("org/acme/webapp/ClassInJarA.class");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSystemServerClass() throws Exception
|
public void testSystemServerClass() throws Exception
|
||||||
{
|
{
|
||||||
_context.getServerClassMatcher().add("org.eclipse.jetty.ee10.webapp.Configuration");
|
_context.getHiddenClassMatcher().add("org.eclipse.jetty.ee10.webapp.Configuration");
|
||||||
_context.getSystemClassMatcher().add("org.eclipse.jetty.ee10.webapp.");
|
_context.getProtectedClassMatcher().add("org.eclipse.jetty.ee10.webapp.");
|
||||||
|
|
||||||
assertCanLoadClass("org.acme.webapp.ClassInJarA");
|
assertCanLoadClass("org.acme.webapp.ClassInJarA");
|
||||||
assertCanLoadClass("org.acme.webapp.ClassInJarB");
|
assertCanLoadClass("org.acme.webapp.ClassInJarB");
|
||||||
|
@ -289,11 +288,11 @@ public class WebAppClassLoaderTest
|
||||||
assertCantLoadClass("org.eclipse.jetty.ee10.webapp.Configuration");
|
assertCantLoadClass("org.eclipse.jetty.ee10.webapp.Configuration");
|
||||||
assertCantLoadClass("org.eclipse.jetty.ee10.webapp.JarScanner");
|
assertCantLoadClass("org.eclipse.jetty.ee10.webapp.JarScanner");
|
||||||
|
|
||||||
_context.getSystemClassMatcher().add("org.acme.webapp.ClassInJarA");
|
_context.getProtectedClassMatcher().add("org.acme.webapp.ClassInJarA");
|
||||||
assertCanLoadResource("org/acme/webapp/ClassInJarA.class");
|
assertCanLoadResource("org/acme/webapp/ClassInJarA.class");
|
||||||
_context.getSystemClassMatcher().remove("org.acme.webapp.ClassInJarA");
|
_context.getProtectedClassMatcher().remove("org.acme.webapp.ClassInJarA");
|
||||||
|
|
||||||
_context.getServerClassMatcher().add("org.acme.webapp.ClassInJarA");
|
_context.getHiddenClassMatcher().add("org.acme.webapp.ClassInJarA");
|
||||||
assertCanLoadResource("org/acme/webapp/ClassInJarA.class");
|
assertCanLoadResource("org/acme/webapp/ClassInJarA.class");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,11 +339,11 @@ public class WebAppClassLoaderTest
|
||||||
// assertEquals(0,resources.get(1).toString().indexOf("jar:file:"));
|
// assertEquals(0,resources.get(1).toString().indexOf("jar:file:"));
|
||||||
// assertEquals(-1,resources.get(2).toString().indexOf("test-classes"));
|
// assertEquals(-1,resources.get(2).toString().indexOf("test-classes"));
|
||||||
|
|
||||||
String[] oldServC = _context.getServerClasses();
|
String[] oldServC = _context.getHiddenClasses();
|
||||||
String[] newServC = new String[oldServC.length + 1];
|
String[] newServC = new String[oldServC.length + 1];
|
||||||
newServC[0] = "org.acme.";
|
newServC[0] = "org.acme.";
|
||||||
System.arraycopy(oldServC, 0, newServC, 1, oldServC.length);
|
System.arraycopy(oldServC, 0, newServC, 1, oldServC.length);
|
||||||
_context.setServerClassMatcher(new ClassMatcher(newServC));
|
_context.setHiddenClassMatcher(new ClassMatcher(newServC));
|
||||||
|
|
||||||
_context.setParentLoaderPriority(true);
|
_context.setParentLoaderPriority(true);
|
||||||
// dump(_context);
|
// dump(_context);
|
||||||
|
@ -361,12 +360,12 @@ public class WebAppClassLoaderTest
|
||||||
// assertEquals(0,resources.get(0).toString().indexOf("jar:file:"));
|
// assertEquals(0,resources.get(0).toString().indexOf("jar:file:"));
|
||||||
// assertEquals(0,resources.get(1).toString().indexOf("file:"));
|
// assertEquals(0,resources.get(1).toString().indexOf("file:"));
|
||||||
|
|
||||||
_context.setServerClassMatcher(new ClassMatcher(oldServC));
|
_context.setHiddenClassMatcher(new ClassMatcher(oldServC));
|
||||||
String[] oldSysC = _context.getSystemClasses();
|
String[] oldSysC = _context.getProtectedClasses();
|
||||||
String[] newSysC = new String[oldSysC.length + 1];
|
String[] newSysC = new String[oldSysC.length + 1];
|
||||||
newSysC[0] = "org.acme.";
|
newSysC[0] = "org.acme.";
|
||||||
System.arraycopy(oldSysC, 0, newSysC, 1, oldSysC.length);
|
System.arraycopy(oldSysC, 0, newSysC, 1, oldSysC.length);
|
||||||
_context.setSystemClassMatcher(new ClassMatcher(newSysC));
|
_context.setProtectedClassMatcher(new ClassMatcher(newSysC));
|
||||||
|
|
||||||
_context.setParentLoaderPriority(true);
|
_context.setParentLoaderPriority(true);
|
||||||
// dump(_context);
|
// dump(_context);
|
||||||
|
|
|
@ -36,6 +36,7 @@ import jakarta.servlet.GenericServlet;
|
||||||
import jakarta.servlet.ServletContext;
|
import jakarta.servlet.ServletContext;
|
||||||
import jakarta.servlet.ServletRequest;
|
import jakarta.servlet.ServletRequest;
|
||||||
import jakarta.servlet.ServletResponse;
|
import jakarta.servlet.ServletResponse;
|
||||||
|
import org.eclipse.jetty.ee.WebAppClassLoading;
|
||||||
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.http.HttpStatus;
|
import org.eclipse.jetty.http.HttpStatus;
|
||||||
|
@ -80,6 +81,7 @@ import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.either;
|
import static org.hamcrest.Matchers.either;
|
||||||
import static org.hamcrest.Matchers.empty;
|
import static org.hamcrest.Matchers.empty;
|
||||||
import static org.hamcrest.Matchers.endsWith;
|
import static org.hamcrest.Matchers.endsWith;
|
||||||
|
import static org.hamcrest.Matchers.hasItem;
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
import static org.hamcrest.Matchers.instanceOf;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
|
@ -128,7 +130,7 @@ public class WebAppContextTest
|
||||||
* @param name the name of the war
|
* @param name the name of the war
|
||||||
* @return the Path of the generated war
|
* @return the Path of the generated war
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception if the war could not be created
|
||||||
*/
|
*/
|
||||||
private Path createWar(Path tempDir, String name) throws Exception
|
private Path createWar(Path tempDir, String name) throws Exception
|
||||||
{
|
{
|
||||||
|
@ -936,4 +938,62 @@ public class WebAppContextTest
|
||||||
|
|
||||||
assertThat(handler.getServer(), sameInstance(server));
|
assertThat(handler.getServer(), sameInstance(server));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddServerClasses() throws Exception
|
||||||
|
{
|
||||||
|
Server server = newServer();
|
||||||
|
|
||||||
|
String testPattern = "org.eclipse.jetty.ee10.webapp.test.";
|
||||||
|
|
||||||
|
WebAppContext.addServerClasses(server, testPattern);
|
||||||
|
|
||||||
|
WebAppContext context = new WebAppContext();
|
||||||
|
context.setContextPath("/");
|
||||||
|
|
||||||
|
Path testPath = MavenPaths.targetTestDir("testAddServerClasses");
|
||||||
|
FS.ensureDirExists(testPath);
|
||||||
|
FS.ensureEmpty(testPath);
|
||||||
|
Path warPath = createWar(testPath, "test.war");
|
||||||
|
context.setBaseResource(context.getResourceFactory().newResource(warPath));
|
||||||
|
|
||||||
|
server.setHandler(context);
|
||||||
|
server.start();
|
||||||
|
|
||||||
|
List<String> serverClasses = List.of(context.getHiddenClasses());
|
||||||
|
assertThat("Should have environment specific test pattern", serverClasses, hasItem(testPattern));
|
||||||
|
assertThat("Should have pattern from defaults", serverClasses, hasItem("org.eclipse.jetty."));
|
||||||
|
assertThat("Should have pattern from JaasConfiguration", serverClasses, hasItem("-org.eclipse.jetty.security.jaas."));
|
||||||
|
for (String defaultServerClass: WebAppClassLoading.DEFAULT_HIDDEN_CLASSES)
|
||||||
|
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(server, testPattern);
|
||||||
|
|
||||||
|
WebAppContext context = new WebAppContext();
|
||||||
|
context.setContextPath("/");
|
||||||
|
Path testPath = MavenPaths.targetTestDir("testAddServerClasses");
|
||||||
|
FS.ensureDirExists(testPath);
|
||||||
|
FS.ensureEmpty(testPath);
|
||||||
|
Path warPath = createWar(testPath, "test.war");
|
||||||
|
context.setBaseResource(context.getResourceFactory().newResource(warPath));
|
||||||
|
|
||||||
|
server.setHandler(context);
|
||||||
|
server.start();
|
||||||
|
|
||||||
|
List<String> systemClasses = List.of(context.getProtectedClasses());
|
||||||
|
assertThat("Should have environment specific test pattern", systemClasses, hasItem(testPattern));
|
||||||
|
assertThat("Should have pattern from defaults", systemClasses, hasItem("javax."));
|
||||||
|
assertThat("Should have pattern from defaults", systemClasses, hasItem("jakarta."));
|
||||||
|
assertThat("Should have pattern from JaasConfiguration", systemClasses, hasItem("org.eclipse.jetty.security.jaas."));
|
||||||
|
for (String defaultSystemClass: WebAppClassLoading.DEFAULT_PROTECTED_CLASSES)
|
||||||
|
assertThat("Should have default patterns", systemClasses, hasItem(defaultSystemClass));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<Configure class="org.eclipse.jetty.ee8.webapp.WebAppContext">
|
<Configure class="org.eclipse.jetty.ee8.webapp.WebAppContext">
|
||||||
<Call name="addServerClassMatcher">
|
<Call name="addServerClassMatcher">
|
||||||
<Arg>
|
<Arg>
|
||||||
<New class="org.eclipse.jetty.ee8.webapp.ClassMatcher">
|
<New class="org.eclipse.jetty.util.ClassMatcher">
|
||||||
<Arg>
|
<Arg>
|
||||||
<Array type="java.lang.String">
|
<Array type="java.lang.String">
|
||||||
<Item>-org.eclipse.jetty.util.Decorator</Item>
|
<Item>-org.eclipse.jetty.util.Decorator</Item>
|
||||||
|
|
|
@ -18,6 +18,10 @@
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-ee</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>jetty-xml</artifactId>
|
<artifactId>jetty-xml</artifactId>
|
||||||
|
|
|
@ -2,22 +2,21 @@
|
||||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_10_0.dtd">
|
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_10_0.dtd">
|
||||||
|
|
||||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||||
<Call class="org.eclipse.jetty.ee8.webapp.WebAppContext" name="addSystemClasses">
|
<Call class="org.eclipse.jetty.ee.WebAppClassLoading" name="addProtectedClasses">
|
||||||
<Arg><Ref refid="Environment"/></Arg>
|
<Arg><Ref refid="Environment"/></Arg>
|
||||||
<Arg>
|
<Arg>
|
||||||
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
|
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
|
||||||
<Arg><Property name="jetty.webapp.addSystemClasses"/></Arg>
|
<Arg><Property name="jetty.webapp.addProtectedClasses" deprecated="jetty.webapp.addSystemClasses"/></Arg>
|
||||||
</Call>
|
</Call>
|
||||||
</Arg>
|
</Arg>
|
||||||
</Call>
|
</Call>
|
||||||
|
|
||||||
<Call class="org.eclipse.jetty.ee8.webapp.WebAppContext" name="addServerClasses">
|
<Call class="org.eclipse.jetty.ee.WebAppClassLoading" name="addHiddenClasses">
|
||||||
<Arg><Ref refid="Environment"/></Arg>
|
<Arg><Ref refid="Environment"/></Arg>
|
||||||
<Arg>
|
<Arg>
|
||||||
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
|
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
|
||||||
<Arg><Property name="jetty.webapp.addServerClasses"/></Arg>
|
<Arg><Property name="jetty.webapp.addHiddenClasses" deprecated="jetty.webapp.addServerClasses"/></Arg>
|
||||||
</Call>
|
</Call>
|
||||||
</Arg>
|
</Arg>
|
||||||
</Call>
|
</Call>
|
||||||
|
|
||||||
</Configure>
|
</Configure>
|
||||||
|
|
|
@ -8,6 +8,7 @@ Without this, only Jetty-specific handlers may be deployed.
|
||||||
ee8
|
ee8
|
||||||
|
|
||||||
[depend]
|
[depend]
|
||||||
|
ee-webapp
|
||||||
ee8-servlet
|
ee8-servlet
|
||||||
ee8-security
|
ee8-security
|
||||||
|
|
||||||
|
@ -18,9 +19,9 @@ etc/jetty-ee8-webapp.xml
|
||||||
lib/jetty-ee8-webapp-${jetty.version}.jar
|
lib/jetty-ee8-webapp-${jetty.version}.jar
|
||||||
|
|
||||||
[ini-template]
|
[ini-template]
|
||||||
## Add to the server wide default jars and packages protected or hidden from webapps.
|
## Add to the environment wide default jars and packages protected or hidden from webapps.
|
||||||
## System classes are protected and cannot be overridden by a webapp.
|
## System (aka Protected) classes cannot be overridden by a webapp.
|
||||||
## Server classes are hidden and cannot be seen by a webapp
|
## Server (aka Hidden) classes cannot be seen by a webapp
|
||||||
## Lists of patterns are comma separated and may be either:
|
## Lists of patterns are comma separated and may be either:
|
||||||
## + a qualified classname e.g. 'com.acme.Foo'
|
## + a qualified classname e.g. 'com.acme.Foo'
|
||||||
## + a package name e.g. 'net.example.'
|
## + a package name e.g. 'net.example.'
|
||||||
|
@ -30,8 +31,8 @@ lib/jetty-ee8-webapp-${jetty.version}.jar
|
||||||
##
|
##
|
||||||
## The +=, operator appends to a CSV list with a comma as needed.
|
## The +=, operator appends to a CSV list with a comma as needed.
|
||||||
##
|
##
|
||||||
#jetty.webapp.addSystemClasses+=,org.example.
|
#jetty.webapp.addProtectedClasses+=,org.example.
|
||||||
#jetty.webapp.addServerClasses+=,org.example.
|
#jetty.webapp.addHiddenClasses+=,org.example.
|
||||||
|
|
||||||
[ini]
|
[ini]
|
||||||
contextHandlerClass=org.eclipse.jetty.ee8.webapp.WebAppContext
|
contextHandlerClass=org.eclipse.jetty.ee8.webapp.WebAppContext
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
|
<Configure class="org.eclipse.jetty.ee9.webapp.WebAppContext">
|
||||||
<Call name="addServerClassMatcher">
|
<Call name="addServerClassMatcher">
|
||||||
<Arg>
|
<Arg>
|
||||||
<New class="org.eclipse.jetty.ee9.webapp.ClassMatcher">
|
<New class="org.eclipse.jetty.util.ClassMatcher">
|
||||||
<Arg>
|
<Arg>
|
||||||
<Array type="java.lang.String">
|
<Array type="java.lang.String">
|
||||||
<Item>-org.eclipse.jetty.util.Decorator</Item>
|
<Item>-org.eclipse.jetty.util.Decorator</Item>
|
||||||
|
|
|
@ -232,6 +232,7 @@ public class TestOSGiUtil
|
||||||
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-jndi").versionAsInProject().start());
|
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-jndi").versionAsInProject().start());
|
||||||
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-osgi").versionAsInProject().start());
|
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-osgi").versionAsInProject().start());
|
||||||
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-client").versionAsInProject().start());
|
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-client").versionAsInProject().start());
|
||||||
|
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-ee").versionAsInProject().start());
|
||||||
res.add(mavenBundle().groupId("org.eclipse.jetty.ee9").artifactId("jetty-ee9-security").versionAsInProject().start());
|
res.add(mavenBundle().groupId("org.eclipse.jetty.ee9").artifactId("jetty-ee9-security").versionAsInProject().start());
|
||||||
res.add(mavenBundle().groupId("org.eclipse.jetty.ee9").artifactId("jetty-ee9-servlet").versionAsInProject().start());
|
res.add(mavenBundle().groupId("org.eclipse.jetty.ee9").artifactId("jetty-ee9-servlet").versionAsInProject().start());
|
||||||
res.add(mavenBundle().groupId("org.eclipse.jetty.ee9").artifactId("jetty-ee9-nested").versionAsInProject().start());
|
res.add(mavenBundle().groupId("org.eclipse.jetty.ee9").artifactId("jetty-ee9-nested").versionAsInProject().start());
|
||||||
|
|
|
@ -42,7 +42,6 @@ import org.eclipse.jetty.session.SessionDataStoreFactory;
|
||||||
import org.eclipse.jetty.session.test.TestSessionDataStoreFactory;
|
import org.eclipse.jetty.session.test.TestSessionDataStoreFactory;
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.junit.jupiter.api.Disabled;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
|
@ -17,6 +17,10 @@
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-ee</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>jetty-xml</artifactId>
|
<artifactId>jetty-xml</artifactId>
|
||||||
|
|
|
@ -2,22 +2,21 @@
|
||||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
|
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||||
|
|
||||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||||
<Call class="org.eclipse.jetty.ee9.webapp.WebAppContext" name="addSystemClasses">
|
<Call class="org.eclipse.jetty.ee.WebAppClassLoading" name="addProtectedClasses">
|
||||||
<Arg><Ref refid="Environment"/></Arg>
|
<Arg><Ref refid="Environment"/></Arg>
|
||||||
<Arg>
|
<Arg>
|
||||||
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
|
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
|
||||||
<Arg><Property name="jetty.webapp.addSystemClasses"/></Arg>
|
<Arg><Property name="jetty.webapp.addProtectedClasses" deprecated="jetty.webapp.addSystemClasses"/></Arg>
|
||||||
</Call>
|
</Call>
|
||||||
</Arg>
|
</Arg>
|
||||||
</Call>
|
</Call>
|
||||||
|
|
||||||
<Call class="org.eclipse.jetty.ee9.webapp.WebAppContext" name="addServerClasses">
|
<Call class="org.eclipse.jetty.ee.WebAppClassLoading" name="addHiddenClasses">
|
||||||
<Arg><Ref refid="Environment"/></Arg>
|
<Arg><Ref refid="Environment"/></Arg>
|
||||||
<Arg>
|
<Arg>
|
||||||
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
|
<Call class="org.eclipse.jetty.util.StringUtil" name="csvSplit">
|
||||||
<Arg><Property name="jetty.webapp.addServerClasses"/></Arg>
|
<Arg><Property name="jetty.webapp.addHiddenClasses" deprecated="jetty.webapp.addServerClasses"/></Arg>
|
||||||
</Call>
|
</Call>
|
||||||
</Arg>
|
</Arg>
|
||||||
</Call>
|
</Call>
|
||||||
|
|
||||||
</Configure>
|
</Configure>
|
||||||
|
|
|
@ -8,6 +8,7 @@ Without this, only Jetty-specific handlers may be deployed.
|
||||||
ee9
|
ee9
|
||||||
|
|
||||||
[depend]
|
[depend]
|
||||||
|
ee-webapp
|
||||||
ee9-servlet
|
ee9-servlet
|
||||||
ee9-security
|
ee9-security
|
||||||
|
|
||||||
|
@ -18,9 +19,9 @@ etc/jetty-ee9-webapp.xml
|
||||||
lib/jetty-ee9-webapp-${jetty.version}.jar
|
lib/jetty-ee9-webapp-${jetty.version}.jar
|
||||||
|
|
||||||
[ini-template]
|
[ini-template]
|
||||||
## Add to the server wide default jars and packages protected or hidden from webapps.
|
## Add to the environment wide default jars and packages protected or hidden from webapps.
|
||||||
## System classes are protected and cannot be overridden by a webapp.
|
## System (aka Protected) classes cannot be overridden by a webapp.
|
||||||
## Server classes are hidden and cannot be seen by a webapp
|
## Server (aka Hidden) classes cannot be seen by a webapp
|
||||||
## Lists of patterns are comma separated and may be either:
|
## Lists of patterns are comma separated and may be either:
|
||||||
## + a qualified classname e.g. 'com.acme.Foo'
|
## + a qualified classname e.g. 'com.acme.Foo'
|
||||||
## + a package name e.g. 'net.example.'
|
## + a package name e.g. 'net.example.'
|
||||||
|
@ -30,8 +31,8 @@ lib/jetty-ee9-webapp-${jetty.version}.jar
|
||||||
##
|
##
|
||||||
## The +=, operator appends to a CSV list with a comma as needed.
|
## The +=, operator appends to a CSV list with a comma as needed.
|
||||||
##
|
##
|
||||||
#jetty.webapp.addSystemClasses+=,org.example.
|
#jetty.webapp.addProtectedClasses+=,org.example.
|
||||||
#jetty.webapp.addServerClasses+=,org.example.
|
#jetty.webapp.addHiddenClasses+=,org.example.
|
||||||
|
|
||||||
[ini]
|
[ini]
|
||||||
contextHandlerClass?=org.eclipse.jetty.ee9.webapp.WebAppContext
|
contextHandlerClass?=org.eclipse.jetty.ee9.webapp.WebAppContext
|
||||||
|
|
|
@ -32,6 +32,7 @@ module org.eclipse.jetty.ee9.webapp
|
||||||
requires transitive java.instrument;
|
requires transitive java.instrument;
|
||||||
requires transitive org.eclipse.jetty.ee9.servlet;
|
requires transitive org.eclipse.jetty.ee9.servlet;
|
||||||
requires transitive org.eclipse.jetty.xml;
|
requires transitive org.eclipse.jetty.xml;
|
||||||
|
requires transitive org.eclipse.jetty.ee;
|
||||||
|
|
||||||
exports org.eclipse.jetty.ee9.webapp;
|
exports org.eclipse.jetty.ee9.webapp;
|
||||||
|
|
||||||
|
|
|
@ -13,786 +13,53 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.ee9.webapp;
|
package org.eclipse.jetty.ee9.webapp;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.AbstractSet;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
|
||||||
import java.util.function.Predicate;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.util.IncludeExcludeSet;
|
import org.eclipse.jetty.util.IncludeExcludeSet;
|
||||||
import org.eclipse.jetty.util.Index;
|
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
|
||||||
import org.eclipse.jetty.util.TypeUtil;
|
|
||||||
import org.eclipse.jetty.util.URIUtil;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A matcher for classes based on package and/or location and/or module/
|
* @deprecated Use org.eclipse.jetty.util.ClassMatcher
|
||||||
* <p>
|
|
||||||
* Performs pattern matching of a class against a set of pattern entries.
|
|
||||||
* A class pattern is a string of one of the forms:<ul>
|
|
||||||
* <li>'org.package.SomeClass' will match a specific class
|
|
||||||
* <li>'org.package.' will match a specific package hierarchy
|
|
||||||
* <li>'org.package.SomeClass$NestedClass ' will match a nested class exactly otherwise.
|
|
||||||
* Nested classes are matched by their containing class. (eg. org.example.MyClass
|
|
||||||
* matches org.example.MyClass$AnyNestedClass)
|
|
||||||
* <li>'file:///some/location/' - A file system directory from which
|
|
||||||
* the class was loaded
|
|
||||||
* <li>'file:///some/location.jar' - The URI of a jar file from which
|
|
||||||
* the class was loaded
|
|
||||||
* <li>'jrt:/modulename' - A Java9 module name</li>
|
|
||||||
* <li>Any of the above patterns preceded by '-' will exclude rather than include the match.
|
|
||||||
* </ul>
|
|
||||||
* When class is initialized from a classpath pattern string, entries
|
|
||||||
* in this string should be separated by ':' (semicolon) or ',' (comma).
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class ClassMatcher extends AbstractSet<String>
|
@Deprecated(since = "12.0.8", forRemoval = true)
|
||||||
|
public class ClassMatcher extends org.eclipse.jetty.util.ClassMatcher
|
||||||
{
|
{
|
||||||
public static class Entry
|
|
||||||
{
|
|
||||||
private final String _pattern;
|
|
||||||
private final String _name;
|
|
||||||
private final boolean _inclusive;
|
|
||||||
|
|
||||||
protected Entry(String name, boolean inclusive)
|
|
||||||
{
|
|
||||||
_name = name;
|
|
||||||
_inclusive = inclusive;
|
|
||||||
_pattern = inclusive ? _name : ("-" + _name);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getPattern()
|
|
||||||
{
|
|
||||||
return _pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getName()
|
|
||||||
{
|
|
||||||
return _name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return _pattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode()
|
|
||||||
{
|
|
||||||
return _pattern.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o)
|
|
||||||
{
|
|
||||||
return (o instanceof Entry) && _pattern.equals(((Entry)o)._pattern);
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isInclusive()
|
|
||||||
{
|
|
||||||
return _inclusive;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class PackageEntry extends Entry
|
|
||||||
{
|
|
||||||
protected PackageEntry(String name, boolean inclusive)
|
|
||||||
{
|
|
||||||
super(name, inclusive);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ClassEntry extends Entry
|
|
||||||
{
|
|
||||||
protected ClassEntry(String name, boolean inclusive)
|
|
||||||
{
|
|
||||||
super(name, inclusive);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class LocationEntry extends Entry
|
|
||||||
{
|
|
||||||
private final Path _path;
|
|
||||||
|
|
||||||
protected LocationEntry(String name, boolean inclusive)
|
|
||||||
{
|
|
||||||
super(name, inclusive);
|
|
||||||
URI uri = URI.create(name);
|
|
||||||
if (!uri.isAbsolute() && !"file".equalsIgnoreCase(uri.getScheme()))
|
|
||||||
throw new IllegalArgumentException("Not a valid file URI: " + name);
|
|
||||||
|
|
||||||
_path = Paths.get(uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Path getPath()
|
|
||||||
{
|
|
||||||
return _path;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class ModuleEntry extends Entry
|
|
||||||
{
|
|
||||||
private final String _module;
|
|
||||||
|
|
||||||
protected ModuleEntry(String name, boolean inclusive)
|
|
||||||
{
|
|
||||||
super(name, inclusive);
|
|
||||||
if (!getName().startsWith("jrt:"))
|
|
||||||
throw new IllegalArgumentException(name);
|
|
||||||
_module = getName().split("/")[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getModule()
|
|
||||||
{
|
|
||||||
return _module;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ByPackage extends AbstractSet<Entry> implements Predicate<String>
|
|
||||||
{
|
|
||||||
private final Index.Mutable<Entry> _entries = new Index.Builder<Entry>()
|
|
||||||
.caseSensitive(true)
|
|
||||||
.mutable()
|
|
||||||
.build();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean test(String name)
|
|
||||||
{
|
|
||||||
return _entries.getBest(name) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<Entry> iterator()
|
|
||||||
{
|
|
||||||
return _entries.keySet().stream().map(_entries::get).iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return _entries.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isEmpty()
|
|
||||||
{
|
|
||||||
return _entries.isEmpty();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean add(Entry entry)
|
|
||||||
{
|
|
||||||
String name = entry.getName();
|
|
||||||
if (entry instanceof ClassEntry)
|
|
||||||
name += "$";
|
|
||||||
else if (!(entry instanceof PackageEntry))
|
|
||||||
throw new IllegalArgumentException(entry.toString());
|
|
||||||
else if (".".equals(name))
|
|
||||||
name = "";
|
|
||||||
|
|
||||||
if (_entries.get(name) != null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return _entries.put(name, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean remove(Object entry)
|
|
||||||
{
|
|
||||||
if (!(entry instanceof Entry))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return _entries.remove(((Entry)entry).getName()) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear()
|
|
||||||
{
|
|
||||||
_entries.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public static class ByClass extends HashSet<Entry> implements Predicate<String>
|
|
||||||
{
|
|
||||||
private final Map<String, Entry> _entries = new HashMap<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean test(String name)
|
|
||||||
{
|
|
||||||
return _entries.containsKey(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<Entry> iterator()
|
|
||||||
{
|
|
||||||
return _entries.values().iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return _entries.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean add(Entry entry)
|
|
||||||
{
|
|
||||||
if (!(entry instanceof ClassEntry))
|
|
||||||
throw new IllegalArgumentException(entry.toString());
|
|
||||||
return _entries.put(entry.getName(), entry) == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean remove(Object entry)
|
|
||||||
{
|
|
||||||
if (!(entry instanceof Entry))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return _entries.remove(((Entry)entry).getName()) != null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ByPackageOrName extends AbstractSet<Entry> implements Predicate<String>
|
|
||||||
{
|
|
||||||
private final ByClass _byClass = new ByClass();
|
|
||||||
private final ByPackage _byPackage = new ByPackage();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean test(String name)
|
|
||||||
{
|
|
||||||
return _byPackage.test(name) || _byClass.test(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<Entry> iterator()
|
|
||||||
{
|
|
||||||
// by package contains all entries (classes are also $ packages).
|
|
||||||
return _byPackage.iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return _byPackage.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean add(Entry entry)
|
|
||||||
{
|
|
||||||
if (entry instanceof PackageEntry)
|
|
||||||
return _byPackage.add(entry);
|
|
||||||
|
|
||||||
if (entry instanceof ClassEntry)
|
|
||||||
{
|
|
||||||
// Add class name to packages also as classes act
|
|
||||||
// as packages for nested classes.
|
|
||||||
boolean added = _byPackage.add(entry);
|
|
||||||
added = _byClass.add(entry) || added;
|
|
||||||
return added;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean remove(Object o)
|
|
||||||
{
|
|
||||||
if (!(o instanceof Entry))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
boolean removedPackage = _byPackage.remove(o);
|
|
||||||
boolean removedClass = _byClass.remove(o);
|
|
||||||
|
|
||||||
return removedPackage || removedClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear()
|
|
||||||
{
|
|
||||||
_byPackage.clear();
|
|
||||||
_byClass.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public static class ByLocation extends HashSet<Entry> implements Predicate<URI>
|
|
||||||
{
|
|
||||||
@Override
|
|
||||||
public boolean test(URI uri)
|
|
||||||
{
|
|
||||||
if ((uri == null) || (!uri.isAbsolute()))
|
|
||||||
return false;
|
|
||||||
if (!uri.getScheme().equals("file"))
|
|
||||||
return false;
|
|
||||||
Path path = Paths.get(uri);
|
|
||||||
|
|
||||||
for (Entry entry : this)
|
|
||||||
{
|
|
||||||
if (!(entry instanceof LocationEntry))
|
|
||||||
throw new IllegalStateException();
|
|
||||||
|
|
||||||
Path entryPath = ((LocationEntry)entry).getPath();
|
|
||||||
|
|
||||||
if (Files.isDirectory(entryPath))
|
|
||||||
{
|
|
||||||
if (path.startsWith(entryPath))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (Files.isSameFile(path, entryPath))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IOException ignore)
|
|
||||||
{
|
|
||||||
// this means there is a FileSystem issue preventing comparison.
|
|
||||||
// Use old technique
|
|
||||||
if (path.equals(entryPath))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
|
||||||
public static class ByModule extends HashSet<Entry> implements Predicate<URI>
|
|
||||||
{
|
|
||||||
private final Index.Mutable<Entry> _entries = new Index.Builder<Entry>()
|
|
||||||
.caseSensitive(true)
|
|
||||||
.mutable()
|
|
||||||
.build();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean test(URI uri)
|
|
||||||
{
|
|
||||||
if ((uri == null) || (!uri.isAbsolute()))
|
|
||||||
return false;
|
|
||||||
if (!uri.getScheme().equalsIgnoreCase("jrt"))
|
|
||||||
return false;
|
|
||||||
String module = uri.getPath();
|
|
||||||
int end = module.indexOf('/', 1);
|
|
||||||
if (end < 1)
|
|
||||||
end = module.length();
|
|
||||||
return _entries.get(module, 1, end - 1) != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<Entry> iterator()
|
|
||||||
{
|
|
||||||
return _entries.keySet().stream().map(_entries::get).iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return _entries.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean add(Entry entry)
|
|
||||||
{
|
|
||||||
if (!(entry instanceof ModuleEntry))
|
|
||||||
throw new IllegalArgumentException(entry.toString());
|
|
||||||
String module = ((ModuleEntry)entry).getModule();
|
|
||||||
|
|
||||||
if (_entries.get(module) != null)
|
|
||||||
return false;
|
|
||||||
_entries.put(module, entry);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean remove(Object entry)
|
|
||||||
{
|
|
||||||
if (!(entry instanceof Entry))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return _entries.remove(((Entry)entry).getName()) != null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ByLocationOrModule extends AbstractSet<Entry> implements Predicate<URI>
|
|
||||||
{
|
|
||||||
private final ByLocation _byLocation = new ByLocation();
|
|
||||||
private final ByModule _byModule = new ByModule();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean test(URI name)
|
|
||||||
{
|
|
||||||
if ((name == null) || (!name.isAbsolute()))
|
|
||||||
return false;
|
|
||||||
return _byLocation.test(name) || _byModule.test(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<Entry> iterator()
|
|
||||||
{
|
|
||||||
Set<Entry> entries = new HashSet<>();
|
|
||||||
entries.addAll(_byLocation);
|
|
||||||
entries.addAll(_byModule);
|
|
||||||
return entries.iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return _byLocation.size() + _byModule.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean add(Entry entry)
|
|
||||||
{
|
|
||||||
if (entry instanceof LocationEntry)
|
|
||||||
return _byLocation.add(entry);
|
|
||||||
if (entry instanceof ModuleEntry)
|
|
||||||
return _byModule.add(entry);
|
|
||||||
|
|
||||||
throw new IllegalArgumentException(entry.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean remove(Object o)
|
|
||||||
{
|
|
||||||
if (o instanceof LocationEntry)
|
|
||||||
return _byLocation.remove(o);
|
|
||||||
if (o instanceof ModuleEntry)
|
|
||||||
return _byModule.remove(o);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear()
|
|
||||||
{
|
|
||||||
_byLocation.clear();
|
|
||||||
_byModule.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<String, Entry> _entries = new HashMap<>();
|
|
||||||
IncludeExcludeSet<Entry, String> _patterns = new IncludeExcludeSet<>(ByPackageOrName.class);
|
|
||||||
IncludeExcludeSet<Entry, URI> _locations = new IncludeExcludeSet<>(ByLocationOrModule.class);
|
|
||||||
|
|
||||||
public ClassMatcher()
|
public ClassMatcher()
|
||||||
{
|
{
|
||||||
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("CopyConstructorMissesField")
|
|
||||||
public ClassMatcher(ClassMatcher patterns)
|
public ClassMatcher(ClassMatcher patterns)
|
||||||
{
|
{
|
||||||
if (patterns != null)
|
super(patterns);
|
||||||
setAll(patterns.getPatterns());
|
}
|
||||||
|
|
||||||
|
public ClassMatcher(org.eclipse.jetty.util.ClassMatcher patterns)
|
||||||
|
{
|
||||||
|
super(patterns);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClassMatcher(String... patterns)
|
public ClassMatcher(String... patterns)
|
||||||
{
|
{
|
||||||
if (patterns != null && patterns.length > 0)
|
super(patterns);
|
||||||
setAll(patterns);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ClassMatcher(String pattern)
|
public ClassMatcher(String pattern)
|
||||||
{
|
{
|
||||||
add(pattern);
|
super(pattern);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean include(String name)
|
protected ClassMatcher(Map<String, Entry> entries, IncludeExcludeSet<Entry, String> patterns, IncludeExcludeSet<Entry, URI> locations)
|
||||||
{
|
{
|
||||||
if (name == null)
|
super(entries, patterns, locations);
|
||||||
return false;
|
|
||||||
return add(newEntry(name, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean include(String... name)
|
|
||||||
{
|
|
||||||
boolean added = false;
|
|
||||||
for (String n : name)
|
|
||||||
{
|
|
||||||
if (n != null)
|
|
||||||
added = add(newEntry(n, true)) || added;
|
|
||||||
}
|
|
||||||
return added;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean exclude(String name)
|
|
||||||
{
|
|
||||||
if (name == null)
|
|
||||||
return false;
|
|
||||||
return add(newEntry(name, false));
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean exclude(String... name)
|
|
||||||
{
|
|
||||||
boolean added = false;
|
|
||||||
for (String n : name)
|
|
||||||
{
|
|
||||||
if (n != null)
|
|
||||||
added = add(newEntry(n, false)) || added;
|
|
||||||
}
|
|
||||||
return added;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean add(String pattern)
|
public ClassMatcher asImmutable()
|
||||||
{
|
{
|
||||||
if (pattern == null)
|
return new ClassMatcher(Map.copyOf(_entries),
|
||||||
return false;
|
_patterns.asImmutable(),
|
||||||
return add(newEntry(pattern));
|
_locations.asImmutable());
|
||||||
}
|
|
||||||
|
|
||||||
public boolean add(String... pattern)
|
|
||||||
{
|
|
||||||
boolean added = false;
|
|
||||||
for (String p : pattern)
|
|
||||||
{
|
|
||||||
if (p != null)
|
|
||||||
added = add(newEntry(p)) || added;
|
|
||||||
}
|
|
||||||
return added;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean add(Entry entry)
|
|
||||||
{
|
|
||||||
if (_entries.containsKey(entry.getPattern()))
|
|
||||||
return false;
|
|
||||||
_entries.put(entry.getPattern(), entry);
|
|
||||||
|
|
||||||
if (entry instanceof LocationEntry || entry instanceof ModuleEntry)
|
|
||||||
{
|
|
||||||
if (entry.isInclusive())
|
|
||||||
_locations.include(entry);
|
|
||||||
else
|
|
||||||
_locations.exclude(entry);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (entry.isInclusive())
|
|
||||||
_patterns.include(entry);
|
|
||||||
else
|
|
||||||
_patterns.exclude(entry);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Entry newEntry(String pattern)
|
|
||||||
{
|
|
||||||
if (pattern.startsWith("-"))
|
|
||||||
return newEntry(pattern.substring(1), false);
|
|
||||||
return newEntry(pattern, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected Entry newEntry(String name, boolean inclusive)
|
|
||||||
{
|
|
||||||
if (name.startsWith("-"))
|
|
||||||
throw new IllegalStateException(name);
|
|
||||||
if (name.startsWith("file:"))
|
|
||||||
return new LocationEntry(name, inclusive);
|
|
||||||
if (name.startsWith("jrt:"))
|
|
||||||
return new ModuleEntry(name, inclusive);
|
|
||||||
if (name.endsWith("."))
|
|
||||||
return new PackageEntry(name, inclusive);
|
|
||||||
return new ClassEntry(name, inclusive);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean remove(Object o)
|
|
||||||
{
|
|
||||||
if (!(o instanceof String))
|
|
||||||
return false;
|
|
||||||
String pattern = (String)o;
|
|
||||||
|
|
||||||
Entry entry = _entries.remove(pattern);
|
|
||||||
if (entry == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
List<Entry> saved = new ArrayList<>(_entries.values());
|
|
||||||
clear();
|
|
||||||
for (Entry e : saved)
|
|
||||||
{
|
|
||||||
add(e);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void clear()
|
|
||||||
{
|
|
||||||
_entries.clear();
|
|
||||||
_patterns.clear();
|
|
||||||
_locations.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Iterator<String> iterator()
|
|
||||||
{
|
|
||||||
return _entries.keySet().iterator();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int size()
|
|
||||||
{
|
|
||||||
return _entries.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the matcher by parsing each classpath pattern in an array
|
|
||||||
*
|
|
||||||
* @param classes array of classpath patterns
|
|
||||||
*/
|
|
||||||
private void setAll(String[] classes)
|
|
||||||
{
|
|
||||||
_entries.clear();
|
|
||||||
addAll(classes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add array of classpath patterns.
|
|
||||||
* @param classes array of classpath patterns
|
|
||||||
*/
|
|
||||||
private void addAll(String[] classes)
|
|
||||||
{
|
|
||||||
if (classes != null)
|
|
||||||
addAll(Arrays.asList(classes));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array of classpath patterns
|
|
||||||
*/
|
|
||||||
public String[] getPatterns()
|
|
||||||
{
|
|
||||||
return toArray(new String[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array of inclusive classpath patterns
|
|
||||||
*/
|
|
||||||
public String[] getInclusions()
|
|
||||||
{
|
|
||||||
return _entries.values().stream().filter(Entry::isInclusive).map(Entry::getName).toArray(String[]::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return array of excluded classpath patterns (without '-' prefix)
|
|
||||||
*/
|
|
||||||
public String[] getExclusions()
|
|
||||||
{
|
|
||||||
return _entries.values().stream().filter(e -> !e.isInclusive()).map(Entry::getName).toArray(String[]::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Match the class name against the pattern
|
|
||||||
*
|
|
||||||
* @param name name of the class to match
|
|
||||||
* @return true if class matches the pattern
|
|
||||||
*/
|
|
||||||
public boolean match(String name)
|
|
||||||
{
|
|
||||||
return _patterns.test(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Match the class name against the pattern
|
|
||||||
*
|
|
||||||
* @param clazz A class to try to match
|
|
||||||
* @return true if class matches the pattern
|
|
||||||
*/
|
|
||||||
public boolean match(Class<?> clazz)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return combine(_patterns, clazz.getName(), _locations, () -> TypeUtil.getLocationOfClass(clazz));
|
|
||||||
}
|
|
||||||
catch (Exception ignored)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean match(String name, URL url)
|
|
||||||
{
|
|
||||||
if (url == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Strip class suffix for name matching
|
|
||||||
if (name.endsWith(".class"))
|
|
||||||
name = name.substring(0, name.length() - 6);
|
|
||||||
|
|
||||||
// Treat path elements as packages for name matching
|
|
||||||
name = StringUtil.replace(name, '/', '.');
|
|
||||||
|
|
||||||
return combine(_patterns, name, _locations, () ->
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return URIUtil.unwrapContainer(url.toURI());
|
|
||||||
}
|
|
||||||
catch (URISyntaxException ignored)
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Match a class against inclusions and exclusions by name and location.
|
|
||||||
* Name based checks are performed before location checks. For a class to match,
|
|
||||||
* it must not be excluded by either name or location, and must either be explicitly
|
|
||||||
* included, or for there to be no inclusions. In the case where the location
|
|
||||||
* of the class is null, it will match if it is included by name, or
|
|
||||||
* if there are no location exclusions.
|
|
||||||
*
|
|
||||||
* @param names configured inclusions and exclusions by name
|
|
||||||
* @param name the name to check
|
|
||||||
* @param locations configured inclusions and exclusions by location
|
|
||||||
* @param location the location of the class (can be null)
|
|
||||||
* @return true if the class is not excluded but is included, or there are
|
|
||||||
* no inclusions. False otherwise.
|
|
||||||
*/
|
|
||||||
static boolean combine(IncludeExcludeSet<Entry, String> names, String name, IncludeExcludeSet<Entry, URI> locations, Supplier<URI> location)
|
|
||||||
{
|
|
||||||
// check the name set
|
|
||||||
Boolean byName = names.isIncludedAndNotExcluded(name);
|
|
||||||
|
|
||||||
// If we excluded by name, then no match
|
|
||||||
if (Boolean.FALSE == byName)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// check the location set
|
|
||||||
URI uri = location.get();
|
|
||||||
Boolean byLocation = uri == null ? null : locations.isIncludedAndNotExcluded(uri);
|
|
||||||
|
|
||||||
// If we excluded by location or couldn't check location exclusion, then no match
|
|
||||||
if (Boolean.FALSE == byLocation || (locations.hasExcludes() && uri == null))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// If there are includes, then we must be included to match.
|
|
||||||
if (names.hasIncludes() || locations.hasIncludes())
|
|
||||||
return byName == Boolean.TRUE || byLocation == Boolean.TRUE;
|
|
||||||
|
|
||||||
// Otherwise there are no includes and it was not excluded, so match
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,8 +60,8 @@ import org.slf4j.LoggerFactory;
|
||||||
* parent loader. Java2 compliant loading, where the parent loader
|
* parent loader. Java2 compliant loading, where the parent loader
|
||||||
* always has priority, can be selected with the
|
* always has priority, can be selected with the
|
||||||
* {@link WebAppContext#setParentLoaderPriority(boolean)}
|
* {@link WebAppContext#setParentLoaderPriority(boolean)}
|
||||||
* method and influenced with {@link WebAppContext#isServerClass(Class)} and
|
* method and influenced with {@link WebAppContext#isHiddenClass(Class)} and
|
||||||
* {@link WebAppContext#isSystemClass(Class)}.
|
* {@link WebAppContext#isProtectedClass(Class)}.
|
||||||
* <p>
|
* <p>
|
||||||
* If no parent class loader is provided, then the current thread
|
* If no parent class loader is provided, then the current thread
|
||||||
* context classloader will be used. If that is null then the
|
* context classloader will be used. If that is null then the
|
||||||
|
@ -429,7 +429,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
||||||
throw new ClassNotFoundException("Bad ClassLoader: returned null for loadClass(" + name + ")");
|
throw new ClassNotFoundException("Bad ClassLoader: returned null for loadClass(" + name + ")");
|
||||||
|
|
||||||
// If the webapp is allowed to see this class
|
// If the webapp is allowed to see this class
|
||||||
if (Boolean.TRUE.equals(__loadServerClasses.get()) || !_context.isServerClass(parentClass))
|
if (Boolean.TRUE.equals(__loadServerClasses.get()) || !_context.isHiddenClass(parentClass))
|
||||||
{
|
{
|
||||||
return parentClass;
|
return parentClass;
|
||||||
}
|
}
|
||||||
|
@ -477,7 +477,7 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
||||||
{
|
{
|
||||||
parentClass = _parent.loadClass(name);
|
parentClass = _parent.loadClass(name);
|
||||||
// If the webapp is allowed to see this class
|
// If the webapp is allowed to see this class
|
||||||
if (Boolean.TRUE.equals(__loadServerClasses.get()) || !_context.isServerClass(parentClass))
|
if (Boolean.TRUE.equals(__loadServerClasses.get()) || !_context.isHiddenClass(parentClass))
|
||||||
{
|
{
|
||||||
return parentClass;
|
return parentClass;
|
||||||
}
|
}
|
||||||
|
@ -609,14 +609,14 @@ public class WebAppClassLoader extends URLClassLoader implements ClassVisibility
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSystemClass(Class<?> clazz)
|
public boolean isProtectedClass(Class<?> clazz)
|
||||||
{
|
{
|
||||||
return _context.isSystemClass(clazz);
|
return _context.isProtectedClass(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isServerClass(Class<?> clazz)
|
public boolean isHiddenClass(Class<?> clazz)
|
||||||
{
|
{
|
||||||
return _context.isServerClass(clazz);
|
return _context.isHiddenClass(clazz);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ 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.WebAppClassLoading;
|
||||||
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.HandlerWrapper;
|
import org.eclipse.jetty.ee9.nested.HandlerWrapper;
|
||||||
|
@ -54,6 +55,7 @@ import org.eclipse.jetty.server.Deployable;
|
||||||
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.ClassMatcher;
|
||||||
import org.eclipse.jetty.util.ExceptionUtil;
|
import org.eclipse.jetty.util.ExceptionUtil;
|
||||||
import org.eclipse.jetty.util.IO;
|
import org.eclipse.jetty.util.IO;
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
|
@ -87,32 +89,35 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
||||||
|
|
||||||
public static final String WEB_DEFAULTS_XML = "org/eclipse/jetty/ee9/webapp/webdefault-ee9.xml";
|
public static final String WEB_DEFAULTS_XML = "org/eclipse/jetty/ee9/webapp/webdefault-ee9.xml";
|
||||||
public static final String ERROR_PAGE = "org.eclipse.jetty.server.error_page";
|
public static final String ERROR_PAGE = "org.eclipse.jetty.server.error_page";
|
||||||
public static final String SERVER_SYS_CLASSES = "org.eclipse.jetty.ee9.webapp.systemClasses";
|
/**
|
||||||
public static final String SERVER_SRV_CLASSES = "org.eclipse.jetty.ee9.webapp.serverClasses";
|
* @deprecated use {@link WebAppClassLoading#PROTECTED_CLASSES_ATTRIBUTE} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated(forRemoval = true, since = "12.0.9")
|
||||||
|
public static final String SERVER_SYS_CLASSES = WebAppClassLoading.PROTECTED_CLASSES_ATTRIBUTE;
|
||||||
|
/**
|
||||||
|
* @deprecated use {@link WebAppClassLoading#HIDDEN_CLASSES_ATTRIBUTE} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated(forRemoval = true, since = "12.0.9")
|
||||||
|
public static final String SERVER_SRV_CLASSES = WebAppClassLoading.HIDDEN_CLASSES_ATTRIBUTE;
|
||||||
|
|
||||||
private static String[] __dftProtectedTargets = {"/WEB-INF", "/META-INF"};
|
private static final String[] __dftProtectedTargets = {"/WEB-INF", "/META-INF"};
|
||||||
|
|
||||||
// System classes are classes that cannot be replaced by
|
/**
|
||||||
// the web application, and they are *always* loaded via
|
* @deprecated use {@link WebAppClassLoading#DEFAULT_PROTECTED_CLASSES}
|
||||||
// system classloader.
|
*/
|
||||||
public static final ClassMatcher __dftSystemClasses = new ClassMatcher(
|
@Deprecated(forRemoval = true, since = "12.0.9")
|
||||||
"java.", // Java SE classes (per servlet spec v2.5 / SRV.9.7.2)
|
public static final org.eclipse.jetty.ee9.webapp.ClassMatcher __dftSystemClasses =
|
||||||
"javax.", // Java SE classes (per servlet spec v2.5 / SRV.9.7.2)
|
new org.eclipse.jetty.ee9.webapp.ClassMatcher(WebAppClassLoading.DEFAULT_PROTECTED_CLASSES);
|
||||||
"jakarta.", // Jakarta classes (per servlet spec v5.0 / Section 15.2.1)
|
|
||||||
"org.xml.", // javax.xml
|
|
||||||
"org.w3c." // javax.xml
|
|
||||||
);
|
|
||||||
|
|
||||||
// Server classes are classes that are hidden from being
|
/**
|
||||||
// loaded by the web application using system classloader,
|
* @deprecated use {@link WebAppClassLoading#DEFAULT_HIDDEN_CLASSES}
|
||||||
// so if web application needs to load any of such classes,
|
*/
|
||||||
// it has to include them in its distribution.
|
@Deprecated(forRemoval = true, since = "12.0.9")
|
||||||
public static final ClassMatcher __dftServerClasses = new ClassMatcher(
|
public static final org.eclipse.jetty.ee9.webapp.ClassMatcher __dftServerClasses =
|
||||||
"org.eclipse.jetty." // hide jetty classes
|
new org.eclipse.jetty.ee9.webapp.ClassMatcher(WebAppClassLoading.DEFAULT_HIDDEN_CLASSES);
|
||||||
);
|
|
||||||
|
|
||||||
private final ClassMatcher _systemClasses = new ClassMatcher(__dftSystemClasses);
|
private final ClassMatcher _systemClasses = new ClassMatcher(WebAppClassLoading.getProtectedClasses(ServletContextHandler.ENVIRONMENT));
|
||||||
private final ClassMatcher _serverClasses = new ClassMatcher(__dftServerClasses);
|
private final ClassMatcher _serverClasses = new ClassMatcher(WebAppClassLoading.getHiddenClasses(ServletContextHandler.ENVIRONMENT));
|
||||||
|
|
||||||
private Configurations _configurations;
|
private Configurations _configurations;
|
||||||
private String _defaultsDescriptor = WEB_DEFAULTS_XML;
|
private String _defaultsDescriptor = WEB_DEFAULTS_XML;
|
||||||
|
@ -746,13 +751,13 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isServerClass(Class<?> clazz)
|
public boolean isHiddenClass(Class<?> clazz)
|
||||||
{
|
{
|
||||||
return _serverClasses.match(clazz);
|
return _serverClasses.match(clazz);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isSystemClass(Class<?> clazz)
|
public boolean isProtectedClass(Class<?> clazz)
|
||||||
{
|
{
|
||||||
return _systemClasses.match(clazz);
|
return _systemClasses.match(clazz);
|
||||||
}
|
}
|
||||||
|
@ -775,23 +780,8 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
||||||
super.setServer(server);
|
super.setServer(server);
|
||||||
if (server != null)
|
if (server != null)
|
||||||
{
|
{
|
||||||
if (__dftSystemClasses.equals(_systemClasses))
|
_systemClasses.add(WebAppClassLoading.getProtectedClasses(server).getPatterns());
|
||||||
{
|
_serverClasses.add(WebAppClassLoading.getHiddenClasses(server).getPatterns());
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1486,38 +1476,31 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
||||||
return _metadata;
|
return _metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addServerClasses(Attributes attributes, String... pattern)
|
/**
|
||||||
|
* Add a Server Class pattern to use for all ee9 WebAppContexts.
|
||||||
|
* @param attributes The {@link Server} instance to add classes to
|
||||||
|
* @param patterns the patterns to use
|
||||||
|
* @see #getServerClassMatcher()
|
||||||
|
* @see #getServerClasses()
|
||||||
|
* @deprecated use {@link WebAppClassLoading#addProtectedClasses(Server, String...)}
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "12.0.8", forRemoval = true)
|
||||||
|
public static void addServerClasses(Attributes attributes, String... patterns)
|
||||||
{
|
{
|
||||||
addClasses(__dftServerClasses, SERVER_SRV_CLASSES, attributes, pattern);
|
WebAppClassLoading.addHiddenClasses(attributes, patterns);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void addSystemClasses(Attributes attributes, String... pattern)
|
/**
|
||||||
|
* Add a System Class pattern to use for all ee9 WebAppContexts.
|
||||||
|
* @param attributes The {@link Server} instance to add classes to
|
||||||
|
* @param patterns the patterns to use
|
||||||
|
* @see #getSystemClassMatcher()
|
||||||
|
* @see #getSystemClasses()
|
||||||
|
* @deprecated use {@link WebAppClassLoading#addHiddenClasses(Server, String...)}
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "12.0.8", forRemoval = true)
|
||||||
|
public static void addSystemClasses(Attributes attributes, String... patterns)
|
||||||
{
|
{
|
||||||
addClasses(__dftSystemClasses, SERVER_SYS_CLASSES, attributes, pattern);
|
WebAppClassLoading.addProtectedClasses(attributes, patterns);
|
||||||
}
|
|
||||||
|
|
||||||
private static void addClasses(ClassMatcher matcher, String attribute, Attributes attributes, 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 = attributes.getAttribute(attribute);
|
|
||||||
if (o instanceof ClassMatcher)
|
|
||||||
{
|
|
||||||
((ClassMatcher)o).add(pattern);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String[] classes;
|
|
||||||
if (o instanceof String[])
|
|
||||||
classes = (String[])o;
|
|
||||||
else
|
|
||||||
classes = matcher.getPatterns();
|
|
||||||
int l = classes.length;
|
|
||||||
classes = Arrays.copyOf(classes, l + pattern.length);
|
|
||||||
System.arraycopy(pattern, 0, classes, l, pattern.length);
|
|
||||||
attributes.setAttribute(attribute, classes);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,307 +0,0 @@
|
||||||
//
|
|
||||||
// ========================================================================
|
|
||||||
// Copyright (c) 1995 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.ee9.webapp;
|
|
||||||
|
|
||||||
import java.net.URI;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
import org.eclipse.jetty.ee9.webapp.ClassMatcher.ByLocationOrModule;
|
|
||||||
import org.eclipse.jetty.ee9.webapp.ClassMatcher.ByPackageOrName;
|
|
||||||
import org.eclipse.jetty.ee9.webapp.ClassMatcher.Entry;
|
|
||||||
import org.eclipse.jetty.util.IncludeExcludeSet;
|
|
||||||
import org.eclipse.jetty.util.TypeUtil;
|
|
||||||
import org.hamcrest.Matchers;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
|
||||||
import static org.hamcrest.Matchers.is;
|
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
|
||||||
|
|
||||||
public class ClassMatcherTest
|
|
||||||
{
|
|
||||||
private final ClassMatcher _pattern = new ClassMatcher();
|
|
||||||
|
|
||||||
protected static Supplier<URI> NULL_SUPPLIER = () -> null;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void before()
|
|
||||||
{
|
|
||||||
_pattern.clear();
|
|
||||||
_pattern.add("org.package.");
|
|
||||||
_pattern.add("-org.excluded.");
|
|
||||||
_pattern.add("org.example.FooBar");
|
|
||||||
_pattern.add("-org.example.Excluded");
|
|
||||||
_pattern.addAll(Arrays.asList(
|
|
||||||
"-org.example.Nested$Minus",
|
|
||||||
"org.example.Nested",
|
|
||||||
"org.example.Nested$Something"));
|
|
||||||
|
|
||||||
assertThat(_pattern, Matchers.containsInAnyOrder(
|
|
||||||
"org.package.",
|
|
||||||
"-org.excluded.",
|
|
||||||
"org.example.FooBar",
|
|
||||||
"-org.example.Excluded",
|
|
||||||
"-org.example.Nested$Minus",
|
|
||||||
"org.example.Nested",
|
|
||||||
"org.example.Nested$Something"
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testClassMatch()
|
|
||||||
{
|
|
||||||
assertTrue(_pattern.match("org.example.FooBar"));
|
|
||||||
assertTrue(_pattern.match("org.example.Nested"));
|
|
||||||
|
|
||||||
assertFalse(_pattern.match("org.example.Unknown"));
|
|
||||||
assertFalse(_pattern.match("org.example.FooBar.Unknown"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testPackageMatch()
|
|
||||||
{
|
|
||||||
assertTrue(_pattern.match("org.package.Something"));
|
|
||||||
assertTrue(_pattern.match("org.package.other.Something"));
|
|
||||||
|
|
||||||
assertFalse(_pattern.match("org.example.Unknown"));
|
|
||||||
assertFalse(_pattern.match("org.example.FooBar.Unknown"));
|
|
||||||
assertFalse(_pattern.match("org.example.FooBarElse"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testExplicitNestedMatch()
|
|
||||||
{
|
|
||||||
assertTrue(_pattern.match("org.example.Nested$Something"));
|
|
||||||
assertFalse(_pattern.match("org.example.Nested$Minus"));
|
|
||||||
assertTrue(_pattern.match("org.example.Nested$Other"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testImplicitNestedMatch()
|
|
||||||
{
|
|
||||||
assertTrue(_pattern.match("org.example.FooBar$Other"));
|
|
||||||
assertTrue(_pattern.match("org.example.Nested$Other"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDoubledNested()
|
|
||||||
{
|
|
||||||
assertTrue(_pattern.match("org.example.Nested$Something$Else"));
|
|
||||||
|
|
||||||
assertFalse(_pattern.match("org.example.Nested$Minus$Else"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testMatchAll()
|
|
||||||
{
|
|
||||||
_pattern.clear();
|
|
||||||
_pattern.add(".");
|
|
||||||
assertTrue(_pattern.match("org.example.Anything"));
|
|
||||||
assertTrue(_pattern.match("org.example.Anything$Else"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCopy()
|
|
||||||
{
|
|
||||||
ClassMatcher copy = new ClassMatcher(_pattern);
|
|
||||||
assertThat(copy.toString(), is(_pattern.toString()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testMatchFundamentalExcludeSpecific()
|
|
||||||
{
|
|
||||||
_pattern.clear();
|
|
||||||
_pattern.add("jakarta.");
|
|
||||||
_pattern.add("-jakarta.ws.rs.", "-jakarta.inject.");
|
|
||||||
assertFalse(_pattern.match("org.example.Anything"));
|
|
||||||
assertTrue(_pattern.match("jakarta.servlet.HttpServlet"));
|
|
||||||
assertFalse(_pattern.match("jakarta.ws.rs.ProcessingException"));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("restriction")
|
|
||||||
@Test
|
|
||||||
public void testIncludedLocations() throws Exception
|
|
||||||
{
|
|
||||||
// jar from JVM classloader
|
|
||||||
URI locString = TypeUtil.getLocationOfClass(String.class);
|
|
||||||
|
|
||||||
// a jar from maven repo jar
|
|
||||||
URI locJunit = TypeUtil.getLocationOfClass(Test.class);
|
|
||||||
|
|
||||||
// class file
|
|
||||||
URI locTest = TypeUtil.getLocationOfClass(ClassMatcherTest.class);
|
|
||||||
|
|
||||||
ClassMatcher pattern = new ClassMatcher();
|
|
||||||
pattern.include("something");
|
|
||||||
assertThat(pattern.match(String.class), is(false));
|
|
||||||
assertThat(pattern.match(Test.class), is(false));
|
|
||||||
assertThat(pattern.match(ClassMatcherTest.class), is(false));
|
|
||||||
|
|
||||||
// Add directory for both JVM classes
|
|
||||||
pattern.include(locString.toASCIIString());
|
|
||||||
|
|
||||||
// Add jar for individual class and classes directory
|
|
||||||
pattern.include(locJunit.toString(), locTest.toString());
|
|
||||||
|
|
||||||
assertThat(pattern.match(String.class), is(true));
|
|
||||||
assertThat(pattern.match(Test.class), is(true));
|
|
||||||
assertThat(pattern.match(ClassMatcherTest.class), is(true));
|
|
||||||
|
|
||||||
pattern.add("-java.lang.String");
|
|
||||||
assertThat(pattern.match(String.class), is(false));
|
|
||||||
assertThat(pattern.match(Test.class), is(true));
|
|
||||||
assertThat(pattern.match(ClassMatcherTest.class), is(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("restriction")
|
|
||||||
@Test
|
|
||||||
public void testIncludedLocationsOrModule() throws Exception
|
|
||||||
{
|
|
||||||
// jar from JVM classloader
|
|
||||||
URI modString = TypeUtil.getLocationOfClass(String.class);
|
|
||||||
// System.err.println(modString);
|
|
||||||
|
|
||||||
// a jar from maven repo jar
|
|
||||||
URI locJunit = TypeUtil.getLocationOfClass(Test.class);
|
|
||||||
// System.err.println(locJunit);
|
|
||||||
|
|
||||||
// class file
|
|
||||||
URI locTest = TypeUtil.getLocationOfClass(ClassMatcherTest.class);
|
|
||||||
// System.err.println(locTest);
|
|
||||||
|
|
||||||
ClassMatcher pattern = new ClassMatcher();
|
|
||||||
pattern.include("something");
|
|
||||||
assertThat(pattern.match(String.class), is(false));
|
|
||||||
assertThat(pattern.match(Test.class), is(false));
|
|
||||||
assertThat(pattern.match(ClassMatcherTest.class), is(false));
|
|
||||||
|
|
||||||
// Add module for all JVM base classes
|
|
||||||
pattern.include("jrt:/java.base");
|
|
||||||
|
|
||||||
// Add jar for individual class and classes directory
|
|
||||||
pattern.include(locJunit.toString(), locTest.toString());
|
|
||||||
|
|
||||||
assertThat(pattern.match(String.class), is(true));
|
|
||||||
assertThat(pattern.match(Test.class), is(true));
|
|
||||||
assertThat(pattern.match(ClassMatcherTest.class), is(true));
|
|
||||||
|
|
||||||
pattern.add("-java.lang.String");
|
|
||||||
assertThat(pattern.match(String.class), is(false));
|
|
||||||
assertThat(pattern.match(Test.class), is(true));
|
|
||||||
assertThat(pattern.match(ClassMatcherTest.class), is(true));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("restriction")
|
|
||||||
@Test
|
|
||||||
public void testExcludeLocationsOrModule() throws Exception
|
|
||||||
{
|
|
||||||
// jar from JVM classloader
|
|
||||||
URI modString = TypeUtil.getLocationOfClass(String.class);
|
|
||||||
assertNotNull(modString);
|
|
||||||
|
|
||||||
// a jar from maven repo jar
|
|
||||||
URI locJunit = TypeUtil.getLocationOfClass(Test.class);
|
|
||||||
assertNotNull(locJunit);
|
|
||||||
|
|
||||||
// class file
|
|
||||||
URI locTest = TypeUtil.getLocationOfClass(ClassMatcherTest.class);
|
|
||||||
assertNotNull(locTest);
|
|
||||||
|
|
||||||
ClassMatcher pattern = new ClassMatcher();
|
|
||||||
|
|
||||||
// include everything
|
|
||||||
pattern.include(".");
|
|
||||||
|
|
||||||
assertThat(pattern.match(String.class), is(true));
|
|
||||||
assertThat(pattern.match(Test.class), is(true));
|
|
||||||
assertThat(pattern.match(ClassMatcherTest.class), is(true));
|
|
||||||
|
|
||||||
// Add directory for both JVM classes
|
|
||||||
pattern.exclude("jrt:/java.base/");
|
|
||||||
|
|
||||||
// Add jar for individual class and classes directory
|
|
||||||
pattern.exclude(locJunit.toASCIIString(), locTest.toASCIIString());
|
|
||||||
|
|
||||||
assertThat(pattern.match(String.class), is(false));
|
|
||||||
assertThat(pattern.match(Test.class), is(false));
|
|
||||||
assertThat(pattern.match(ClassMatcherTest.class), is(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testWithNullLocation() throws Exception
|
|
||||||
{
|
|
||||||
ClassMatcher matcher = new ClassMatcher();
|
|
||||||
|
|
||||||
IncludeExcludeSet<Entry, String> names = new IncludeExcludeSet<>(ByPackageOrName.class);
|
|
||||||
IncludeExcludeSet<Entry, URI> locations = new IncludeExcludeSet<>(ByLocationOrModule.class);
|
|
||||||
|
|
||||||
//Test no name or location includes or excludes - should match
|
|
||||||
assertThat(ClassMatcher.combine(names, "a.b.c", locations, NULL_SUPPLIER), is(true));
|
|
||||||
|
|
||||||
names.include(matcher.newEntry("a.b.", true));
|
|
||||||
names.exclude(matcher.newEntry("d.e.", false));
|
|
||||||
|
|
||||||
//Test explicit include by name no locations - should match
|
|
||||||
assertThat(ClassMatcher.combine(names, "a.b.c", locations, NULL_SUPPLIER), is(true));
|
|
||||||
|
|
||||||
//Test explicit exclude by name no locations - should not match
|
|
||||||
assertThat(ClassMatcher.combine(names, "d.e.f", locations, NULL_SUPPLIER), is(false));
|
|
||||||
|
|
||||||
//Test include by name with location includes - should match
|
|
||||||
locations.include(matcher.newEntry("file:/foo/bar", true));
|
|
||||||
assertThat(ClassMatcher.combine(names, "a.b.c", locations, NULL_SUPPLIER), is(true));
|
|
||||||
|
|
||||||
//Test include by name but with location exclusions - should not match
|
|
||||||
locations.clear();
|
|
||||||
locations.exclude(matcher.newEntry("file:/high/low", false));
|
|
||||||
assertThat(ClassMatcher.combine(names, "a.b.c", locations, NULL_SUPPLIER), is(false));
|
|
||||||
|
|
||||||
//Test neither included or excluded by name, but with location exclusions - should not match
|
|
||||||
assertThat(ClassMatcher.combine(names, "g.b.r", locations, NULL_SUPPLIER), is(false));
|
|
||||||
|
|
||||||
//Test neither included nor excluded by name, but with location inclusions - should not match
|
|
||||||
locations.clear();
|
|
||||||
locations.include(matcher.newEntry("file:/foo/bar", true));
|
|
||||||
assertThat(ClassMatcher.combine(names, "g.b.r", locations, NULL_SUPPLIER), is(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testLarge()
|
|
||||||
{
|
|
||||||
ClassMatcher pattern = new ClassMatcher();
|
|
||||||
for (int i = 0; i < 500; i++)
|
|
||||||
{
|
|
||||||
assertTrue(pattern.add("n" + i + "." + Integer.toHexString(100 + i) + ".Name"));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 500; i++)
|
|
||||||
{
|
|
||||||
assertTrue(pattern.match("n" + i + "." + Integer.toHexString(100 + i) + ".Name"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testJvmModule()
|
|
||||||
{
|
|
||||||
URI uri = TypeUtil.getLocationOfClass(String.class);
|
|
||||||
assertThat(uri, notNullValue());
|
|
||||||
assertThat(uri.getScheme(), is("jrt"));
|
|
||||||
assertThat(uri.getPath(), is("/java.base"));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -26,9 +26,9 @@ import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.jetty.server.Server;
|
import org.eclipse.jetty.server.Server;
|
||||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||||
|
import org.eclipse.jetty.util.ClassMatcher;
|
||||||
import org.eclipse.jetty.util.IO;
|
import org.eclipse.jetty.util.IO;
|
||||||
import org.eclipse.jetty.util.component.LifeCycle;
|
import org.eclipse.jetty.util.component.LifeCycle;
|
||||||
import org.eclipse.jetty.util.resource.FileSystemPool;
|
|
||||||
import org.eclipse.jetty.util.resource.Resource;
|
import org.eclipse.jetty.util.resource.Resource;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
@ -37,7 +37,6 @@ import org.junit.jupiter.api.Test;
|
||||||
import static org.eclipse.jetty.toolchain.test.ExtraMatchers.ordered;
|
import static org.eclipse.jetty.toolchain.test.ExtraMatchers.ordered;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.contains;
|
import static org.hamcrest.Matchers.contains;
|
||||||
import static org.hamcrest.Matchers.empty;
|
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
import static org.hamcrest.Matchers.nullValue;
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
|
|
|
@ -34,6 +34,7 @@ import jakarta.servlet.GenericServlet;
|
||||||
import jakarta.servlet.ServletContext;
|
import jakarta.servlet.ServletContext;
|
||||||
import jakarta.servlet.ServletRequest;
|
import jakarta.servlet.ServletRequest;
|
||||||
import jakarta.servlet.ServletResponse;
|
import jakarta.servlet.ServletResponse;
|
||||||
|
import org.eclipse.jetty.ee.WebAppClassLoading;
|
||||||
import org.eclipse.jetty.ee9.nested.ContextHandler;
|
import org.eclipse.jetty.ee9.nested.ContextHandler;
|
||||||
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;
|
||||||
|
@ -79,6 +80,7 @@ import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.empty;
|
import static org.hamcrest.Matchers.empty;
|
||||||
import static org.hamcrest.Matchers.endsWith;
|
import static org.hamcrest.Matchers.endsWith;
|
||||||
|
import static org.hamcrest.Matchers.hasItem;
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
import static org.hamcrest.Matchers.instanceOf;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
|
@ -116,7 +118,7 @@ public class WebAppContextTest
|
||||||
* @param name the name of the war
|
* @param name the name of the war
|
||||||
* @return the Path of the generated war
|
* @return the Path of the generated war
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception if the war cannot be created
|
||||||
*/
|
*/
|
||||||
private Path createWar(Path tempDir, String name) throws Exception
|
private Path createWar(Path tempDir, String name) throws Exception
|
||||||
{
|
{
|
||||||
|
@ -847,4 +849,63 @@ public class WebAppContextTest
|
||||||
extLibs = extLibs.toAbsolutePath();
|
extLibs = extLibs.toAbsolutePath();
|
||||||
assertThat("URL[0]", urls[0].toURI(), is(extLibs.toUri()));
|
assertThat("URL[0]", urls[0].toURI(), is(extLibs.toUri()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddServerClasses() throws Exception
|
||||||
|
{
|
||||||
|
Server server = newServer();
|
||||||
|
|
||||||
|
String testPattern = "org.eclipse.jetty.ee9.webapp.test.";
|
||||||
|
|
||||||
|
WebAppContext.addServerClasses(server, testPattern);
|
||||||
|
|
||||||
|
WebAppContext context = new WebAppContext();
|
||||||
|
context.setContextPath("/");
|
||||||
|
Path testPath = MavenPaths.targetTestDir("testAddServerClasses");
|
||||||
|
FS.ensureDirExists(testPath);
|
||||||
|
FS.ensureEmpty(testPath);
|
||||||
|
Path warPath = createWar(testPath, "test.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 defaults", serverClasses, hasItem("org.eclipse.jetty."));
|
||||||
|
assertThat("Should have pattern from JaasConfiguration", serverClasses, hasItem("-org.eclipse.jetty.security.jaas."));
|
||||||
|
for (String defaultServerClass: WebAppClassLoading.DEFAULT_HIDDEN_CLASSES)
|
||||||
|
assertThat("Should have default patterns", serverClasses, hasItem(defaultServerClass));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddSystemClasses() throws Exception
|
||||||
|
{
|
||||||
|
Server server = newServer();
|
||||||
|
|
||||||
|
String testPattern = "org.eclipse.jetty.ee9.webapp.test.";
|
||||||
|
|
||||||
|
WebAppContext.addSystemClasses(server, testPattern);
|
||||||
|
|
||||||
|
WebAppContext context = new WebAppContext();
|
||||||
|
context.setContextPath("/");
|
||||||
|
Path testPath = MavenPaths.targetTestDir("testAddServerClasses");
|
||||||
|
FS.ensureDirExists(testPath);
|
||||||
|
FS.ensureEmpty(testPath);
|
||||||
|
Path warPath = createWar(testPath, "test.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 defaults", systemClasses, hasItem("javax."));
|
||||||
|
assertThat("Should have pattern from defaults", systemClasses, hasItem("jakarta."));
|
||||||
|
assertThat("Should have pattern from JaasConfiguration", systemClasses, hasItem("org.eclipse.jetty.security.jaas."));
|
||||||
|
for (String defaultSystemClass : WebAppClassLoading.DEFAULT_PROTECTED_CLASSES)
|
||||||
|
{
|
||||||
|
assertThat("Should have default patterns", systemClasses, hasItem(defaultSystemClass));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,10 @@
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>jetty-deploy</artifactId>
|
<artifactId>jetty-deploy</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
|
<artifactId>jetty-ee</artifactId>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.eclipse.jetty</groupId>
|
<groupId>org.eclipse.jetty</groupId>
|
||||||
<artifactId>jetty-hazelcast</artifactId>
|
<artifactId>jetty-hazelcast</artifactId>
|
||||||
|
|
|
@ -21,5 +21,5 @@ basehome:modules/logging/jetty
|
||||||
lib/logging/jetty-slf4j-impl-${jetty.version}.jar
|
lib/logging/jetty-slf4j-impl-${jetty.version}.jar
|
||||||
|
|
||||||
[ini]
|
[ini]
|
||||||
jetty.webapp.addServerClasses+=,org.eclipse.jetty.logging.
|
jetty.webapp.addHiddenClasses+=,org.eclipse.jetty.logging.
|
||||||
jetty.webapp.addServerClasses+=,${jetty.home.uri}/lib/logging/
|
jetty.webapp.addHiddenClasses+=,${jetty.home.uri}/lib/logging/
|
||||||
|
|
|
@ -31,7 +31,7 @@ lib/logging/log4j-${log4j.version}.jar
|
||||||
|
|
||||||
[ini]
|
[ini]
|
||||||
log4j.version?=1.2.17
|
log4j.version?=1.2.17
|
||||||
jetty.webapp.addServerClasses+=,org.apache.log4j.
|
jetty.webapp.addHiddenClasses+=,org.apache.log4j.
|
||||||
|
|
||||||
|
|
||||||
[license]
|
[license]
|
||||||
|
|
|
@ -28,7 +28,7 @@ lib/logging/log4j-core-${log4j2.version}.jar
|
||||||
|
|
||||||
[ini]
|
[ini]
|
||||||
log4j2.version?=@log4j2.version@
|
log4j2.version?=@log4j2.version@
|
||||||
jetty.webapp.addServerClasses+=,org.apache.logging.log4j.
|
jetty.webapp.addHiddenClasses+=,org.apache.logging.log4j.
|
||||||
|
|
||||||
[license]
|
[license]
|
||||||
Log4j is released under the Apache 2.0 license.
|
Log4j is released under the Apache 2.0 license.
|
||||||
|
|
|
@ -25,7 +25,7 @@ lib/logging/logback-core-${logback.version}.jar
|
||||||
|
|
||||||
[ini]
|
[ini]
|
||||||
logback.version?=@logback.version@
|
logback.version?=@logback.version@
|
||||||
jetty.webapp.addServerClasses+=,ch.qos.logback.
|
jetty.webapp.addHiddenClasses+=,ch.qos.logback.
|
||||||
|
|
||||||
[license]
|
[license]
|
||||||
Logback: the reliable, generic, fast and flexible logging framework.
|
Logback: the reliable, generic, fast and flexible logging framework.
|
||||||
|
|
|
@ -16,4 +16,4 @@ lib/logging/slf4j-api-${slf4j.version}.jar
|
||||||
|
|
||||||
[ini]
|
[ini]
|
||||||
slf4j.version?=@slf4j.version@
|
slf4j.version?=@slf4j.version@
|
||||||
jetty.webapp.addServerClasses+=,org.slf4j.
|
jetty.webapp.addHiddenClasses+=,org.slf4j.
|
||||||
|
|
|
@ -17,4 +17,4 @@ http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
|
|
||||||
[ini]
|
[ini]
|
||||||
## Hide the gcloud libraries from deployed webapps
|
## Hide the gcloud libraries from deployed webapps
|
||||||
jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/gcloud/
|
jetty.webapp.addHiddenClasses+=,${jetty.base.uri}/lib/gcloud/
|
||||||
|
|
|
@ -10,4 +10,4 @@ internal
|
||||||
|
|
||||||
[ini]
|
[ini]
|
||||||
## Hide the infinispan libraries from deployed webapps
|
## Hide the infinispan libraries from deployed webapps
|
||||||
jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/infinispan/
|
jetty.webapp.addHiddenClasses+=,${jetty.base.uri}/lib/infinispan/
|
||||||
|
|
|
@ -9,4 +9,4 @@ infinispan
|
||||||
|
|
||||||
[ini]
|
[ini]
|
||||||
## Hide the infinispan libraries from deployed webapps
|
## Hide the infinispan libraries from deployed webapps
|
||||||
jetty.webapp.addServerClasses+=,${jetty.base.uri}/lib/infinispan/
|
jetty.webapp.addHiddenClasses+=,${jetty.base.uri}/lib/infinispan/
|
||||||
|
|
|
@ -101,7 +101,7 @@ public class DemoModulesTests extends AbstractJettyHomeTest
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@MethodSource("provideEnvironmentsToTest")
|
@MethodSource("provideEnvironmentsToTest")
|
||||||
public void testDemoAddServerClasses(String env) throws Exception
|
public void testDemoAddHiddenClasses(String env) throws Exception
|
||||||
{
|
{
|
||||||
Path jettyBase = newTestJettyBaseDirectory();
|
Path jettyBase = newTestJettyBaseDirectory();
|
||||||
String jettyVersion = System.getProperty("jettyVersion");
|
String jettyVersion = System.getProperty("jettyVersion");
|
||||||
|
@ -124,14 +124,14 @@ public class DemoModulesTests extends AbstractJettyHomeTest
|
||||||
assertTrue(runListConfig.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
|
assertTrue(runListConfig.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
|
||||||
assertEquals(0, runListConfig.getExitValue(), "Exit value");
|
assertEquals(0, runListConfig.getExitValue(), "Exit value");
|
||||||
// Example of what we expect
|
// Example of what we expect
|
||||||
// jetty.webapp.addServerClasses = org.eclipse.jetty.logging.,${jetty.home.uri}/lib/logging/,org.slf4j.,${jetty.base.uri}/lib/bouncycastle/
|
// jetty.webapp.addHiddenClasses = org.eclipse.jetty.logging.,${jetty.home.uri}/lib/logging/,org.slf4j.,${jetty.base.uri}/lib/bouncycastle/
|
||||||
String addServerKey = " jetty.webapp.addServerClasses = ";
|
String addServerKey = " jetty.webapp.addHiddenClasses = ";
|
||||||
String addServerClasses = runListConfig.getLogs().stream()
|
String addServerClasses = runListConfig.getLogs().stream()
|
||||||
.filter(s -> s.startsWith(addServerKey))
|
.filter(s -> s.startsWith(addServerKey))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElseThrow(() ->
|
.orElseThrow(() ->
|
||||||
new NoSuchElementException("Unable to find [" + addServerKey + "]"));
|
new NoSuchElementException("Unable to find [" + addServerKey + "]"));
|
||||||
assertThat("'jetty.webapp.addServerClasses' entry count",
|
assertThat("'jetty.webapp.addHiddenClasses' entry count",
|
||||||
addServerClasses.split(",").length,
|
addServerClasses.split(",").length,
|
||||||
greaterThan(1));
|
greaterThan(1));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue