* Fixes #8913 - Review Jetty XML syntax to allow calling JDK methods Now `<Call>`, `<Get>` and `<Set>` elements can use the `class` attribute to specify the exact class to perform method lookup. Improved support for `<Property>`, `<SystemProperty>` and `<Env>` so that attribute `name` is now optional (as specified in the DTD), and a `deprecated` attribute may be present instead. This is necessary to terminally deprecate properties that have no replacement. Signed-off-by: Simone Bordet <simone.bordet@gmail.com>
This commit is contained in:
parent
8de1bad511
commit
b43e2e5600
|
@ -74,6 +74,8 @@ var mystring = new String();
|
||||||
|
|
||||||
If an object with the id `mystring` already exists, then it is not created again but rather just referenced.
|
If an object with the id `mystring` already exists, then it is not created again but rather just referenced.
|
||||||
|
|
||||||
|
Within element `<Configure>`, the created object (if any) is in xref:og-xml-syntax-scope[scope] and may be the implicit target of other, nested, elements.
|
||||||
|
|
||||||
Typically the `<Configure>` element is used to configure a `Server` instance or `ContextHandler` subclasses such as `WebAppContext` that represent web applications.
|
Typically the `<Configure>` element is used to configure a `Server` instance or `ContextHandler` subclasses such as `WebAppContext` that represent web applications.
|
||||||
|
|
||||||
[[og-xml-syntax-arg]]
|
[[og-xml-syntax-arg]]
|
||||||
|
@ -187,12 +189,38 @@ This is equivalent to the following Java code:
|
||||||
var myhost = InetAddress.getByName("jdk.java.net");
|
var myhost = InetAddress.getByName("jdk.java.net");
|
||||||
----
|
----
|
||||||
|
|
||||||
|
The `class` attribute (or `<Class>` element) can also be used to specify the Java class or interface to use to lookup the non-``static`` method name.
|
||||||
|
This is necessary when the object in scope, onto which the `<Call>` would be applied, is an instance of a class that is not visible to Jetty classes, or not accessible because it is not `public`.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
[source,xml,subs=normal]
|
||||||
|
----
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://www.eclipse.org/jetty/configure_10_0.dtd">
|
||||||
|
|
||||||
|
<Configure>
|
||||||
|
<Call class="java.util.concurrent.Executors" name="newSingleThreadScheduledExecutor">
|
||||||
|
#<Call class="java.util.concurrent.ExecutorService" name="shutdown" />#
|
||||||
|
</Call>
|
||||||
|
</Configure>
|
||||||
|
----
|
||||||
|
|
||||||
|
In the example above, `Executors.newSingleThreadScheduledExecutor()` returns an object whose class is a private JDK implementation class.
|
||||||
|
Without an explicit `class` attribute (or `<Class>` element), it is not possible to invoke the method `shutdown()` when it is obtained via reflection from the private JDK implementation class, because while the method is `public`, the private JDK implementation class is not, therefore this exception is thrown:
|
||||||
|
|
||||||
|
[source]
|
||||||
|
----
|
||||||
|
java.lang.IllegalAccessException: class org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration (in module org.eclipse.jetty.xml) cannot access a member of class java.util.concurrent.Executors$DelegatedExecutorService (in module java.base) with modifiers "public"
|
||||||
|
----
|
||||||
|
|
||||||
|
The solution is to explicitly use the `class` attribute (or `<Class>` element) of the `<Call>` element that is invoking the `shutdown()` method, specifying a publicly accessible class or interface that the object in scope extends or implements (in the example above `java.util.concurrent.ExecutorService`).
|
||||||
|
|
||||||
[[og-xml-syntax-get]]
|
[[og-xml-syntax-get]]
|
||||||
===== `<Get>`
|
===== `<Get>`
|
||||||
|
|
||||||
Element `<Get>` retrieves the value of a JavaBean property specified by the mandatory `name` attribute.
|
Element `<Get>` retrieves the value of a JavaBean property specified by the mandatory `name` attribute.
|
||||||
|
|
||||||
If the JavaBean property is `foo` (or `Foo`), `<Get>` first attempts to invoke _method_ `getFoo()`; failing that, attempts to retrieve the value from _field_ `foo` (or `Foo`).
|
If the JavaBean property is `foo` (or `Foo`), `<Get>` first attempts to invoke _method_ `getFoo()` or _method_ `isFoo()`; failing that, attempts to retrieve the value from _field_ `foo` (or `Foo`).
|
||||||
|
|
||||||
[source,xml]
|
[source,xml]
|
||||||
----
|
----
|
||||||
|
@ -212,6 +240,8 @@ If the JavaBean property is `foo` (or `Foo`), `<Get>` first attempts to invoke _
|
||||||
</Configure>
|
</Configure>
|
||||||
----
|
----
|
||||||
|
|
||||||
|
The `class` attribute (or `<Class>` element) allows to perform `static` calls, or to lookup the getter method from the specified class, as described in the xref:og-xml-syntax-call[`<Call>` section].
|
||||||
|
|
||||||
[[og-xml-syntax-set]]
|
[[og-xml-syntax-set]]
|
||||||
===== `<Set>`
|
===== `<Set>`
|
||||||
|
|
||||||
|
@ -235,6 +265,8 @@ If the JavaBean property is `foo` (or `Foo`), `<Set>` first attempts to invoke _
|
||||||
</Configure>
|
</Configure>
|
||||||
----
|
----
|
||||||
|
|
||||||
|
The `class` attribute (or `<Class>` element) allows to perform `static` calls, or to lookup the setter method from the specified class, as described in the xref:og-xml-syntax-call[`<Call>` section].
|
||||||
|
|
||||||
[[og-xml-syntax-map]]
|
[[og-xml-syntax-map]]
|
||||||
===== `<Map>` and `<Entry>`
|
===== `<Map>` and `<Entry>`
|
||||||
|
|
||||||
|
|
|
@ -522,9 +522,7 @@ public class XmlConfiguration
|
||||||
String propertyValue = null;
|
String propertyValue = null;
|
||||||
|
|
||||||
Class<?> oClass = nodeClass(node);
|
Class<?> oClass = nodeClass(node);
|
||||||
if (oClass != null)
|
if (oClass == null)
|
||||||
obj = null;
|
|
||||||
else
|
|
||||||
oClass = obj.getClass();
|
oClass = obj.getClass();
|
||||||
|
|
||||||
// Look for a property value
|
// Look for a property value
|
||||||
|
@ -553,9 +551,9 @@ public class XmlConfiguration
|
||||||
value = propertyValue;
|
value = propertyValue;
|
||||||
Object[] arg = {value};
|
Object[] arg = {value};
|
||||||
|
|
||||||
Class<?>[] vClass = {Object.class};
|
Class<?> vClass = Object.class;
|
||||||
if (value != null)
|
if (value != null)
|
||||||
vClass[0] = value.getClass();
|
vClass = value.getClass();
|
||||||
|
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("XML {}.{} ({})", (obj != null ? obj.toString() : oClass.getName()), setter, value);
|
LOG.debug("XML {}.{} ({})", (obj != null ? obj.toString() : oClass.getName()), setter, value);
|
||||||
|
@ -582,8 +580,8 @@ public class XmlConfiguration
|
||||||
// Try for native match
|
// Try for native match
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Field type = vClass[0].getField("TYPE");
|
Field type = vClass.getField("TYPE");
|
||||||
vClass[0] = (Class<?>)type.get(null);
|
vClass = (Class<?>)type.get(null);
|
||||||
Method set = oClass.getMethod(setter, vClass);
|
Method set = oClass.getMethod(setter, vClass);
|
||||||
invokeMethod(set, obj, arg);
|
invokeMethod(set, obj, arg);
|
||||||
return;
|
return;
|
||||||
|
@ -715,7 +713,7 @@ public class XmlConfiguration
|
||||||
}
|
}
|
||||||
|
|
||||||
// No Joy
|
// No Joy
|
||||||
String message = oClass + "." + setter + "(" + vClass[0] + ")";
|
String message = oClass + "." + setter + "(" + vClass + ")";
|
||||||
if (types != null)
|
if (types != null)
|
||||||
message += ". Found setters for " + types;
|
message += ". Found setters for " + types;
|
||||||
NoSuchMethodException failure = new NoSuchMethodException(message);
|
NoSuchMethodException failure = new NoSuchMethodException(message);
|
||||||
|
@ -828,19 +826,11 @@ public class XmlConfiguration
|
||||||
|
|
||||||
Class<?> oClass;
|
Class<?> oClass;
|
||||||
if (clazz != null)
|
if (clazz != null)
|
||||||
{
|
|
||||||
// static call
|
|
||||||
oClass = Loader.loadClass(clazz);
|
oClass = Loader.loadClass(clazz);
|
||||||
obj = null;
|
|
||||||
}
|
|
||||||
else if (obj != null)
|
else if (obj != null)
|
||||||
{
|
|
||||||
oClass = obj.getClass();
|
oClass = obj.getClass();
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
throw new IllegalArgumentException(node.toString());
|
throw new IllegalArgumentException(node.toString());
|
||||||
}
|
|
||||||
|
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("XML get {}", name);
|
LOG.debug("XML get {}", name);
|
||||||
|
@ -906,19 +896,11 @@ public class XmlConfiguration
|
||||||
|
|
||||||
Class<?> oClass;
|
Class<?> oClass;
|
||||||
if (clazz != null)
|
if (clazz != null)
|
||||||
{
|
|
||||||
// static call
|
|
||||||
oClass = Loader.loadClass(clazz);
|
oClass = Loader.loadClass(clazz);
|
||||||
obj = null;
|
|
||||||
}
|
|
||||||
else if (obj != null)
|
else if (obj != null)
|
||||||
{
|
|
||||||
oClass = obj.getClass();
|
oClass = obj.getClass();
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
throw new IllegalArgumentException(node.toString());
|
throw new IllegalArgumentException(node.toString());
|
||||||
}
|
|
||||||
|
|
||||||
if (LOG.isDebugEnabled())
|
if (LOG.isDebugEnabled())
|
||||||
LOG.debug("XML call {}", name);
|
LOG.debug("XML call {}", name);
|
||||||
|
@ -955,10 +937,6 @@ public class XmlConfiguration
|
||||||
Object[] arguments = args.applyTo(method);
|
Object[] arguments = args.applyTo(method);
|
||||||
if (arguments == null)
|
if (arguments == null)
|
||||||
continue;
|
continue;
|
||||||
if (Modifier.isStatic(method.getModifiers()) != (obj == null))
|
|
||||||
continue;
|
|
||||||
if ((obj == null) && method.getDeclaringClass() != oClass)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -1177,13 +1155,16 @@ public class XmlConfiguration
|
||||||
{
|
{
|
||||||
AttrOrElementNode aoeNode = new AttrOrElementNode(node, "Id", "Name", "Deprecated", "Default");
|
AttrOrElementNode aoeNode = new AttrOrElementNode(node, "Id", "Name", "Deprecated", "Default");
|
||||||
String id = aoeNode.getString("Id");
|
String id = aoeNode.getString("Id");
|
||||||
String name = aoeNode.getString("Name", true);
|
String name = aoeNode.getString("Name", false);
|
||||||
List<Object> deprecated = aoeNode.getList("Deprecated");
|
List<Object> deprecated = aoeNode.getList("Deprecated");
|
||||||
String dftValue = aoeNode.getString("Default");
|
String dftValue = aoeNode.getString("Default");
|
||||||
|
|
||||||
|
if (name == null && deprecated.isEmpty())
|
||||||
|
throw new IllegalStateException("Invalid <Property> element");
|
||||||
|
|
||||||
// Look for a value
|
// Look for a value
|
||||||
Map<String, String> properties = _configuration.getProperties();
|
Map<String, String> properties = _configuration.getProperties();
|
||||||
String value = properties.get(name);
|
String value = name == null ? null : properties.get(name);
|
||||||
|
|
||||||
// Look for a deprecated name value
|
// Look for a deprecated name value
|
||||||
String alternate = null;
|
String alternate = null;
|
||||||
|
@ -1191,13 +1172,22 @@ public class XmlConfiguration
|
||||||
{
|
{
|
||||||
for (Object d : deprecated)
|
for (Object d : deprecated)
|
||||||
{
|
{
|
||||||
String v = properties.get(StringUtil.valueOf(d));
|
if (d == null)
|
||||||
|
continue;
|
||||||
|
String v = properties.get(d.toString());
|
||||||
if (v != null)
|
if (v != null)
|
||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null)
|
||||||
LOG.warn("Property '{}' is deprecated, use '{}' instead", d, name);
|
{
|
||||||
|
if (name == null)
|
||||||
|
LOG.warn("Property '{}' is deprecated, no replacement available", d);
|
||||||
|
else
|
||||||
|
LOG.warn("Property '{}' is deprecated, use '{}' instead", d, name);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
LOG.warn("Property '{}' is deprecated, value from '{}' used", d, name);
|
{
|
||||||
|
LOG.warn("Property '{}' is deprecated, value from '{}' used instead", d, name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (alternate == null)
|
if (alternate == null)
|
||||||
alternate = v;
|
alternate = v;
|
||||||
|
@ -1228,12 +1218,15 @@ public class XmlConfiguration
|
||||||
{
|
{
|
||||||
AttrOrElementNode aoeNode = new AttrOrElementNode(node, "Id", "Name", "Deprecated", "Default");
|
AttrOrElementNode aoeNode = new AttrOrElementNode(node, "Id", "Name", "Deprecated", "Default");
|
||||||
String id = aoeNode.getString("Id");
|
String id = aoeNode.getString("Id");
|
||||||
String name = aoeNode.getString("Name", true);
|
String name = aoeNode.getString("Name", false);
|
||||||
List<Object> deprecated = aoeNode.getList("Deprecated");
|
List<Object> deprecated = aoeNode.getList("Deprecated");
|
||||||
String dftValue = aoeNode.getString("Default");
|
String dftValue = aoeNode.getString("Default");
|
||||||
|
|
||||||
|
if (name == null && deprecated.isEmpty())
|
||||||
|
throw new IllegalStateException("Invalid <SystemProperty> element");
|
||||||
|
|
||||||
// Look for a value
|
// Look for a value
|
||||||
String value = System.getProperty(name);
|
String value = name == null ? null : System.getProperty(name);
|
||||||
|
|
||||||
// Look for a deprecated name value
|
// Look for a deprecated name value
|
||||||
String alternate = null;
|
String alternate = null;
|
||||||
|
@ -1247,9 +1240,16 @@ public class XmlConfiguration
|
||||||
if (v != null)
|
if (v != null)
|
||||||
{
|
{
|
||||||
if (value == null)
|
if (value == null)
|
||||||
LOG.warn("SystemProperty '{}' is deprecated, use '{}' instead", d, name);
|
{
|
||||||
|
if (name == null)
|
||||||
|
LOG.warn("SystemProperty '{}' is deprecated, no replacement available", d);
|
||||||
|
else
|
||||||
|
LOG.warn("SystemProperty '{}' is deprecated, use '{}' instead", d, name);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
LOG.warn("SystemProperty '{}' is deprecated, value from '{}' used", d, name);
|
LOG.warn("SystemProperty '{}' is deprecated, value from '{}' used", d, name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (alternate == null)
|
if (alternate == null)
|
||||||
alternate = v;
|
alternate = v;
|
||||||
|
@ -1281,22 +1281,30 @@ public class XmlConfiguration
|
||||||
{
|
{
|
||||||
AttrOrElementNode aoeNode = new AttrOrElementNode(node, "Id", "Name", "Deprecated", "Default");
|
AttrOrElementNode aoeNode = new AttrOrElementNode(node, "Id", "Name", "Deprecated", "Default");
|
||||||
String id = aoeNode.getString("Id");
|
String id = aoeNode.getString("Id");
|
||||||
String name = aoeNode.getString("Name", true);
|
String name = aoeNode.getString("Name", false);
|
||||||
List<Object> deprecated = aoeNode.getList("Deprecated");
|
List<Object> deprecated = aoeNode.getList("Deprecated");
|
||||||
String dftValue = aoeNode.getString("Default");
|
String dftValue = aoeNode.getString("Default");
|
||||||
|
|
||||||
|
if (name == null && deprecated.isEmpty())
|
||||||
|
throw new IllegalStateException("Invalid <Env> element");
|
||||||
|
|
||||||
// Look for a value
|
// Look for a value
|
||||||
String value = System.getenv(name);
|
String value = name == null ? null : System.getenv(name);
|
||||||
|
|
||||||
// Look for a deprecated name value
|
// Look for a deprecated name value
|
||||||
if (value == null && !deprecated.isEmpty())
|
if (value == null && !deprecated.isEmpty())
|
||||||
{
|
{
|
||||||
for (Object d : deprecated)
|
for (Object d : deprecated)
|
||||||
{
|
{
|
||||||
value = System.getenv(StringUtil.valueOf(d));
|
if (d == null)
|
||||||
|
continue;
|
||||||
|
value = System.getenv(d.toString());
|
||||||
if (value != null)
|
if (value != null)
|
||||||
{
|
{
|
||||||
LOG.warn("Property '{}' is deprecated, use '{}' instead", d, name);
|
if (name == null)
|
||||||
|
LOG.warn("Property '{}' is deprecated, no replacement available", d);
|
||||||
|
else
|
||||||
|
LOG.warn("Property '{}' is deprecated, use '{}' instead", d, name);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -286,7 +286,7 @@ System Property Element.
|
||||||
This element allows JVM System properties to be retrieved as
|
This element allows JVM System properties to be retrieved as
|
||||||
part of the value of elements such as Set, Put, Arg, etc.
|
part of the value of elements such as Set, Put, Arg, etc.
|
||||||
The name attribute specifies the property name and the optional
|
The name attribute specifies the property name and the optional
|
||||||
default argument provides a default value.
|
default attribute provides a default value.
|
||||||
|
|
||||||
<SystemProperty name="Test" default="value" />
|
<SystemProperty name="Test" default="value" />
|
||||||
|
|
||||||
|
@ -303,7 +303,7 @@ Environment variable Element.
|
||||||
This element allows OS Environment variables to be retrieved as
|
This element allows OS Environment variables to be retrieved as
|
||||||
part of the value of elements such as Set, Put, Arg, etc.
|
part of the value of elements such as Set, Put, Arg, etc.
|
||||||
The name attribute specifies the env variable name and the optional
|
The name attribute specifies the env variable name and the optional
|
||||||
default argument provides a default value.
|
default attribute provides a default value.
|
||||||
|
|
||||||
<Env name="Test" default="value" />
|
<Env name="Test" default="value" />
|
||||||
|
|
||||||
|
@ -311,7 +311,6 @@ This is equivalent to:
|
||||||
|
|
||||||
String v=System.getEnv("Test");
|
String v=System.getEnv("Test");
|
||||||
if (v==null) v="value";
|
if (v==null) v="value";
|
||||||
|
|
||||||
-->
|
-->
|
||||||
<!ELEMENT Env (Id?,Name?,Deprecated*,Default?) >
|
<!ELEMENT Env (Id?,Name?,Deprecated*,Default?) >
|
||||||
<!ATTLIST Env %ID_ATTR; %NAME_ATTR; %DEPRECATED_ATTR; %DEFAULT_ATTR; >
|
<!ATTLIST Env %ID_ATTR; %NAME_ATTR; %DEPRECATED_ATTR; %DEFAULT_ATTR; >
|
||||||
|
@ -321,7 +320,7 @@ This is equivalent to:
|
||||||
Property Element.
|
Property Element.
|
||||||
This element allows arbitrary properties to be retrieved by name.
|
This element allows arbitrary properties to be retrieved by name.
|
||||||
The name attribute specifies the property name and the optional
|
The name attribute specifies the property name and the optional
|
||||||
default argument provides a default value.
|
default attribute provides a default value.
|
||||||
-->
|
-->
|
||||||
<!ELEMENT Property (Id?,Name?,Deprecated*,Default?) >
|
<!ELEMENT Property (Id?,Name?,Deprecated*,Default?) >
|
||||||
<!ATTLIST Property %ID_ATTR; %NAME_ATTR; %DEPRECATED_ATTR; %DEFAULT_ATTR; >
|
<!ATTLIST Property %ID_ATTR; %NAME_ATTR; %DEPRECATED_ATTR; %DEFAULT_ATTR; >
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.io.PrintStream;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.nio.channels.SocketChannel;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -29,9 +30,11 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentMap;
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
import javax.net.ssl.SSLSocketFactory;
|
||||||
|
|
||||||
import org.eclipse.jetty.logging.JettyLevel;
|
import org.eclipse.jetty.logging.JettyLevel;
|
||||||
import org.eclipse.jetty.logging.JettyLogger;
|
import org.eclipse.jetty.logging.JettyLogger;
|
||||||
|
@ -39,7 +42,6 @@ import org.eclipse.jetty.logging.StdErrAppender;
|
||||||
import org.eclipse.jetty.toolchain.test.FS;
|
import org.eclipse.jetty.toolchain.test.FS;
|
||||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
|
||||||
import org.eclipse.jetty.util.annotation.Name;
|
import org.eclipse.jetty.util.annotation.Name;
|
||||||
import org.eclipse.jetty.util.resource.PathResource;
|
import org.eclipse.jetty.util.resource.PathResource;
|
||||||
import org.eclipse.jetty.util.resource.Resource;
|
import org.eclipse.jetty.util.resource.Resource;
|
||||||
|
@ -48,7 +50,6 @@ import org.junit.jupiter.api.Assumptions;
|
||||||
import org.junit.jupiter.api.RepeatedTest;
|
import org.junit.jupiter.api.RepeatedTest;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.condition.OS;
|
import org.junit.jupiter.api.condition.OS;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.Arguments;
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
import org.junit.jupiter.params.provider.MethodSource;
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
|
@ -74,19 +75,19 @@ import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
@ExtendWith(WorkDirExtension.class)
|
|
||||||
public class XmlConfigurationTest
|
public class XmlConfigurationTest
|
||||||
{
|
{
|
||||||
public WorkDir workDir;
|
|
||||||
|
|
||||||
private static final String STRING_ARRAY_XML = "<Array type=\"String\"><Item type=\"String\">String1</Item><Item type=\"String\">String2</Item></Array>";
|
private static final String STRING_ARRAY_XML = "<Array type=\"String\"><Item type=\"String\">String1</Item><Item type=\"String\">String2</Item></Array>";
|
||||||
private static final String INT_ARRAY_XML = "<Array type=\"int\"><Item type=\"int\">1</Item><Item type=\"int\">2</Item></Array>";
|
private static final String INT_ARRAY_XML = "<Array type=\"int\"><Item type=\"int\">1</Item><Item type=\"int\">2</Item></Array>";
|
||||||
|
|
||||||
|
public WorkDir workDir;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMortBay() throws Exception
|
public void testMortBay() throws Exception
|
||||||
{
|
{
|
||||||
URL url = XmlConfigurationTest.class.getResource("mortbay.xml");
|
URL url = XmlConfigurationTest.class.getResource("mortbay.xml");
|
||||||
Resource resource = Resource.newResource(url);
|
Resource resource = Resource.newResource(url);
|
||||||
|
assertNotNull(resource);
|
||||||
XmlConfiguration configuration = new XmlConfiguration(resource);
|
XmlConfiguration configuration = new XmlConfiguration(resource);
|
||||||
configuration.configure();
|
configuration.configure();
|
||||||
}
|
}
|
||||||
|
@ -269,7 +270,7 @@ public class XmlConfigurationTest
|
||||||
|
|
||||||
public XmlConfiguration asXmlConfiguration(String rawXml) throws IOException, SAXException
|
public XmlConfiguration asXmlConfiguration(String rawXml) throws IOException, SAXException
|
||||||
{
|
{
|
||||||
if (rawXml.indexOf("!DOCTYPE") < 0)
|
if (!rawXml.contains("!DOCTYPE"))
|
||||||
rawXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
|
rawXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
|
||||||
"<!DOCTYPE Configure PUBLIC \"-//Jetty//Configure//EN\" \"https://www.eclipse.org/jetty/configure_10_0.dtd\">\n" +
|
"<!DOCTYPE Configure PUBLIC \"-//Jetty//Configure//EN\" \"https://www.eclipse.org/jetty/configure_10_0.dtd\">\n" +
|
||||||
rawXml;
|
rawXml;
|
||||||
|
@ -278,7 +279,7 @@ public class XmlConfigurationTest
|
||||||
|
|
||||||
public XmlConfiguration asXmlConfiguration(String filename, String rawXml) throws IOException, SAXException
|
public XmlConfiguration asXmlConfiguration(String filename, String rawXml) throws IOException, SAXException
|
||||||
{
|
{
|
||||||
if (rawXml.indexOf("!DOCTYPE") < 0)
|
if (!rawXml.contains("!DOCTYPE"))
|
||||||
rawXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
|
rawXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
|
||||||
"<!DOCTYPE Configure PUBLIC \"-//Jetty//Configure//EN\" \"https://www.eclipse.org/jetty/configure_10_0.dtd\">\n" +
|
"<!DOCTYPE Configure PUBLIC \"-//Jetty//Configure//EN\" \"https://www.eclipse.org/jetty/configure_10_0.dtd\">\n" +
|
||||||
rawXml;
|
rawXml;
|
||||||
|
@ -348,7 +349,7 @@ public class XmlConfigurationTest
|
||||||
tc.testField1 = -1;
|
tc.testField1 = -1;
|
||||||
configuration.configure(tc);
|
configuration.configure(tc);
|
||||||
assertEquals(-1, tc.testField1);
|
assertEquals(-1, tc.testField1);
|
||||||
assertEquals(configuration.getIdMap().get("test"), null);
|
assertNull(configuration.getIdMap().get("test"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -745,7 +746,7 @@ public class XmlConfigurationTest
|
||||||
{
|
{
|
||||||
List<Method> methods = Arrays.stream(TestOrder.class.getMethods()).filter(m -> "call".equals(m.getName())).collect(Collectors.toList());
|
List<Method> methods = Arrays.stream(TestOrder.class.getMethods()).filter(m -> "call".equals(m.getName())).collect(Collectors.toList());
|
||||||
Collections.shuffle(methods);
|
Collections.shuffle(methods);
|
||||||
Collections.sort(methods, XmlConfiguration.EXECUTABLE_COMPARATOR);
|
methods.sort(XmlConfiguration.EXECUTABLE_COMPARATOR);
|
||||||
assertThat(methods, Matchers.contains(
|
assertThat(methods, Matchers.contains(
|
||||||
TestOrder.class.getMethod("call"),
|
TestOrder.class.getMethod("call"),
|
||||||
TestOrder.class.getMethod("call", int.class),
|
TestOrder.class.getMethod("call", int.class),
|
||||||
|
@ -1465,7 +1466,7 @@ public class XmlConfigurationTest
|
||||||
assertThat("BarNamed has foo", bar.getFoo(), is("foozball"));
|
assertThat("BarNamed has foo", bar.getFoo(), is("foozball"));
|
||||||
});
|
});
|
||||||
|
|
||||||
List<String> warnings = Arrays.stream(logBytes.toString(UTF_8.name()).split(System.lineSeparator()))
|
List<String> warnings = Arrays.stream(logBytes.toString(UTF_8).split(System.lineSeparator()))
|
||||||
.filter(line -> line.contains(":WARN"))
|
.filter(line -> line.contains(":WARN"))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
@ -1495,7 +1496,7 @@ public class XmlConfigurationTest
|
||||||
assertThat("BarNamed has foo", bar.getFoo(), is("foozball"));
|
assertThat("BarNamed has foo", bar.getFoo(), is("foozball"));
|
||||||
});
|
});
|
||||||
|
|
||||||
List<String> warnings = Arrays.stream(logBytes.toString(UTF_8.name()).split(System.lineSeparator()))
|
List<String> warnings = Arrays.stream(logBytes.toString(UTF_8).split(System.lineSeparator()))
|
||||||
.filter(line -> line.contains(":WARN :"))
|
.filter(line -> line.contains(":WARN :"))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
@ -1564,7 +1565,7 @@ public class XmlConfigurationTest
|
||||||
assertThat("Zeds[0]", zeds.get(0), is("plain-zero"));
|
assertThat("Zeds[0]", zeds.get(0), is("plain-zero"));
|
||||||
});
|
});
|
||||||
|
|
||||||
List<String> warnings = Arrays.stream(logBytes.toString(UTF_8.name()).split(System.lineSeparator()))
|
List<String> warnings = Arrays.stream(logBytes.toString(UTF_8).split(System.lineSeparator()))
|
||||||
.filter(line -> line.contains(":WARN :"))
|
.filter(line -> line.contains(":WARN :"))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
|
|
||||||
|
@ -1590,6 +1591,7 @@ public class XmlConfigurationTest
|
||||||
configuration.configure();
|
configuration.configure();
|
||||||
last = configuration;
|
last = configuration;
|
||||||
}
|
}
|
||||||
|
assertNotNull(last);
|
||||||
return last.getIdMap();
|
return last.getIdMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1628,7 +1630,7 @@ public class XmlConfigurationTest
|
||||||
|
|
||||||
ByteArrayOutputStream logBytes = captureLoggingBytes(xmlConfiguration::configure);
|
ByteArrayOutputStream logBytes = captureLoggingBytes(xmlConfiguration::configure);
|
||||||
|
|
||||||
String[] lines = logBytes.toString(UTF_8.name()).split(System.lineSeparator());
|
String[] lines = logBytes.toString(UTF_8).split(System.lineSeparator());
|
||||||
List<String> warnings = Arrays.stream(lines)
|
List<String> warnings = Arrays.stream(lines)
|
||||||
.filter(line -> line.contains(":WARN :"))
|
.filter(line -> line.contains(":WARN :"))
|
||||||
.filter(line -> line.contains(testClass.getSimpleName()))
|
.filter(line -> line.contains(testClass.getSimpleName()))
|
||||||
|
@ -1765,6 +1767,94 @@ public class XmlConfigurationTest
|
||||||
assertEquals(baseDir.resolve("etc/keystore").toString(), resolved);
|
assertEquals(baseDir.resolve("etc/keystore").toString(), resolved);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testPropertyNoNameAttributeWithDeprecatedAttribute() throws Exception
|
||||||
|
{
|
||||||
|
XmlConfiguration configuration = asXmlConfiguration(
|
||||||
|
"<Configure class=\"org.eclipse.jetty.xml.TestConfiguration\">" +
|
||||||
|
" <Set name=\"TestString\">" +
|
||||||
|
" <Property deprecated=\"jetty.deprecated\" />" +
|
||||||
|
" </Set>" +
|
||||||
|
"</Configure>"
|
||||||
|
);
|
||||||
|
|
||||||
|
String value = "deprecated";
|
||||||
|
configuration.getProperties().put("jetty.deprecated", value);
|
||||||
|
|
||||||
|
TestConfiguration tc = new TestConfiguration();
|
||||||
|
configuration.configure(tc);
|
||||||
|
|
||||||
|
assertThat(tc.getTestString(), is(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVirtualGetWithClassAttribute() throws Exception
|
||||||
|
{
|
||||||
|
// SocketChannel.open() returns an internal class
|
||||||
|
// that cannot be accessed, so <Get> must specify the
|
||||||
|
// class to use to lookup the 'getLocalAddress' method.
|
||||||
|
XmlConfiguration configuration = asXmlConfiguration(
|
||||||
|
"<Configure class=\"org.eclipse.jetty.xml.TestConfiguration\">" +
|
||||||
|
" <Set name=\"Test\">" +
|
||||||
|
" <Call class=\"java.nio.channels.SocketChannel\" name=\"open\">" +
|
||||||
|
" <Get class=\"java.nio.channels.SocketChannel\" name=\"localAddress\" />" +
|
||||||
|
" </Call>" +
|
||||||
|
" </Set>" +
|
||||||
|
"</Configure>"
|
||||||
|
);
|
||||||
|
|
||||||
|
TestConfiguration tc = new TestConfiguration();
|
||||||
|
configuration.configure(tc);
|
||||||
|
|
||||||
|
assertThat(tc.testObject, instanceOf(SocketChannel.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVirtualSetWithClassAttribute() throws Exception
|
||||||
|
{
|
||||||
|
// SSLSocketFactory.getDefault().createSocket() returns an internal
|
||||||
|
// class that cannot be accessed, so <Set> must specify the
|
||||||
|
// class to use to lookup the 'setNeedClientAuth' method.
|
||||||
|
XmlConfiguration configuration = asXmlConfiguration(
|
||||||
|
"<Configure class=\"org.eclipse.jetty.xml.TestConfiguration\">" +
|
||||||
|
" <Set name=\"Test\">" +
|
||||||
|
" <Call class=\"javax.net.ssl.SSLSocketFactory\" name=\"getDefault\">" +
|
||||||
|
" <Call class=\"javax.net.ssl.SSLSocketFactory\" name=\"createSocket\">" +
|
||||||
|
" <Set class=\"javax.net.ssl.SSLSocket\" name=\"needClientAuth\">true</Set>" +
|
||||||
|
" </Call>" +
|
||||||
|
" </Call>" +
|
||||||
|
" </Set>" +
|
||||||
|
"</Configure>"
|
||||||
|
);
|
||||||
|
|
||||||
|
TestConfiguration tc = new TestConfiguration();
|
||||||
|
configuration.configure(tc);
|
||||||
|
|
||||||
|
assertThat(tc.testObject, instanceOf(SSLSocketFactory.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testVirtualCallWithClassAttribute() throws Exception
|
||||||
|
{
|
||||||
|
// Executors.newSingleThreadScheduledExecutor() returns an
|
||||||
|
// internal class that cannot be accessed, so <Call> must
|
||||||
|
// specify the class to use to lookup the 'shutdown' method.
|
||||||
|
XmlConfiguration configuration = asXmlConfiguration(
|
||||||
|
"<Configure class=\"org.eclipse.jetty.xml.TestConfiguration\">" +
|
||||||
|
" <Set name=\"Test\">" +
|
||||||
|
" <Call class=\"java.util.concurrent.Executors\" name=\"newSingleThreadScheduledExecutor\">" +
|
||||||
|
" <Call class=\"java.util.concurrent.ExecutorService\" name=\"shutdown\" />" +
|
||||||
|
" </Call>" +
|
||||||
|
" </Set>" +
|
||||||
|
"</Configure>"
|
||||||
|
);
|
||||||
|
|
||||||
|
TestConfiguration tc = new TestConfiguration();
|
||||||
|
configuration.configure(tc);
|
||||||
|
|
||||||
|
assertThat(tc.testObject, instanceOf(ScheduledExecutorService.class));
|
||||||
|
}
|
||||||
|
|
||||||
private ByteArrayOutputStream captureLoggingBytes(ThrowableAction action) throws Exception
|
private ByteArrayOutputStream captureLoggingBytes(ThrowableAction action) throws Exception
|
||||||
{
|
{
|
||||||
Logger slf4jLogger = LoggerFactory.getLogger(XmlConfiguration.class);
|
Logger slf4jLogger = LoggerFactory.getLogger(XmlConfiguration.class);
|
||||||
|
|
Loading…
Reference in New Issue