Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Jetty 12.0.x 12191 debug listener #12231

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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -202,40 +202,92 @@ $ java -jar $JETTY_HOME/start.jar -Dmyapps.dir=/opt/myapps
[[env-context-xml]]
== Deploying Environment Specific Context XML Files

A xref:xml/index.adoc[Jetty context XML file] file can be applied to _all_ webapps deployed to a particular `environment` by adding a file named `{ee-all}.properties` containing the location of the file.
xref:xml/index.adoc[Jetty context XML file] files can be applied to _all_ webapps deployed to a particular `environment`.

This environment-specific Jetty context XML file will be applied to the webapps _before_ any context XML file associated with the webapp.
Thus, it can be used to configure general defaults to all webapps for a given `environment`, allowing a webapp-specific context XML file to further refine or override that configuration.
Add a properties file to the deployment directory that contains a property naming the location of the xml file to apply.
The properties file name must be prefixed by the name of the `environment`.
For example `ee8.properties, ee8-more.properties ee8-other.properties` would all apply to the `ee8` environment.
janbartel marked this conversation as resolved.
Show resolved Hide resolved

The properties files contain at minimum one property whose name is prefixed with `org.eclipse.jetty.deploy.environmentXml`.
janbartel marked this conversation as resolved.
Show resolved Hide resolved
So for example `org.eclipse.jetty.deploy.environmentXml, org.eclipse.jetty.deploy.environmentXml.more, org.eclipse.jetty.deploy.environmentXml.other` are all acceptable as names.
Each property configures the location of a context xml file to apply to a context when it is being created and deployed.
janbartel marked this conversation as resolved.
Show resolved Hide resolved
The location may be either absolute or relative to _the parent of the deployment directory_.
So if your webapp deployment directory is `$JETTY_BASE/webapps`, then `$JETTY_BASE` will be used to resolve any relative filenames.

All environment-specific Jetty context XML files will be applied to the webapp _before_ any context XML file associated with the webapp.
The order in which they are applied is determined by _the name of the properties that define them_.

IMPORTANT: The contents of the environment specific context XML file may only contain references to classes appropriate for that environment.

The `{ee-all}.properties` file must be in the same directory as the webapp being deployed.
It must contain the property `jetty.deploy.environmentXml` set to the location of the context XML file.
The location may be either absolute or relative to the parent of the deployment directory (usually `$JETTY_BASE`).
For example, given the previous example of a `$JETTY_BASE/webapps/wiki.xml` and its accompanying `$JETTY_BASE/webapps/wiki.properties` file that declares the `wiki` webapp should be deployed to environment `{ee-current}`, files called `$JETTY_BASE/webapps/{ee-current}.properties` and `$JETTY_BASE/webapps/{ee-current}-feature.properties` can be defined to further configure the webapp.

For example, given the previous example of a `$JETTY_BASE/webapps/wiki.xml` and its accompanying `$JETTY_BASE/webapps/wiki.properties` file that declares the `wiki` webapp should be deployed to environment `{ee-current}`, a file called `$JETTY_BASE/webapps/{ee-current}.properties` can be defined containing the following:
The `{ee-current}.properties` file contains:

.{ee-current}.properties
[,properties,subs=attributes+]
----
jetty.deploy.environmentXml=etc/{ee-current}-context.xml
----

The `{ee-current}-feature.properties` file contains:

.{ee-current}-feature.properties
[,properties,subs=attributes+]
----
jetty.deploy.environmentXml.feature=etc/{ee-current}-feature.xml
----

The `{ee-current}-context.xml` file contains:

.{ee-current}-context.xml
[,xml,subs="attributes+,+quotes"]
----
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://jetty.org/configure_10_0.dtd">

<Configure id="wac" class="org.eclipse.jetty.{ee-current}.webapp.WebAppContext">
<Call name="setAttribute">
<Arg>common</Arg>
<Arg>value</Arg>
</Call>
</Configure>
----

The `{ee-current}-feature.xml` file contains:

.{ee-current}-feature.xml
[,xml,subs="attributes+,+quotes"]
----
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://jetty.org/configure_10_0.dtd">

<Configure id="wac" class="org.eclipse.jetty.{ee-current}.webapp.WebAppContext">
<Call name="addEventListener">
<Arg>
<New class="com.example.MyListenerFeature"/>
</Arg>
</Call>
</Configure>
----


The directory structure would look like this:

.directory structure
[,properties,subs=attributes+]
----
$JETTY_BASE
├── etc
│ └── {ee-current}-context.xml
└── webapps
├── {ee-current}.properties
├── wiki.properties
└── wiki.xml
|- etc
│ |-{ee-current}-context.xml
| |-{ee-current}-feature.xml
|- webapps
|-{ee-current}.properties
|-{ee-current}-feature.properties
|-wiki.properties
|- wiki.xml
----

The contents of the `$JETTY_BASE/etc/{ee-current}-context.xml` file will be applied to the `wiki` webapp instance _before_ the `wiki.xml`, allowing the contents of the latter to override the contents of the former.
The contents of the `$JETTY_BASE/etc/{ee-current}-context.xml` then `$JETTY_BASE/etc/{ee-current}-feature.xml` files will be applied to the `wiki` webapp instance _before_ `wiki.xml`, allowing the contents of the latter to override the contents of the former.

== WEB-INF/jetty-{ee-all}-web.xml

Expand Down Expand Up @@ -264,7 +316,7 @@ The JNDI entry must be _defined_ in a xref:jndi/index.adoc#xml[Jetty XML file],
<Configure id="wac" class="org.eclipse.jetty.{ee-current}.webapp.WebAppContext">
<Set name="contextPath">/mywebapp</Set>
<Set name="war">/opt/webapps/mywebapp.war</Set>
#<New class="org.eclipse.jetty.plus.jndi.Resource">
<New class="org.eclipse.jetty.plus.jndi.Resource">
<Arg><Ref refid="wac"/></Arg>
<Arg>jdbc/myds</Arg>
<Arg>
Expand All @@ -274,7 +326,7 @@ The JNDI entry must be _defined_ in a xref:jndi/index.adoc#xml[Jetty XML file],
<Set name="password">password</Set>
</New>
</Arg>
</New>#
</New>
</Configure>
----

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,20 @@ It is recommended that you consider configuring also the property `jetty.crossor
When set to `true`, clients send cookies and authentication headers in cross-origin requests to your domain.
When set to `false`, cookies and authentication headers are not sent.

[[eeN-debug]]
== Module `{ee-all}-debug`
include::{jetty-home}/modules/ee10-debug.mod[tags=description]

Enabling this module produces a log file that is useful to debug incoming traffic.
It will log entry and exit points of HTTP requests as well as the response code.

Multiple versions of this module exist (`{ee-all}-debug`) to support each Jakarta EE platform's version of the Java Servlet specification.
Jetty's configuration properties are identical across these versions; the configuration properties for the `{ee-current}-debug` Jetty module are:

----
include::{jetty-home}/modules/ee10-debug.mod[tags=ini-template]
----

[[eeN-deploy]]
== Module `{ee-all}-deploy`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,15 @@
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.Properties;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.eclipse.jetty.deploy.App;
Expand Down Expand Up @@ -302,7 +305,10 @@ else if (Supplier.class.isAssignableFrom(context.getClass()))
initializeContextPath(contextHandler, path);

if (Files.isDirectory(path))
{
contextHandler.setBaseResource(ResourceFactory.of(this).newResource(path));
System.err.println("SET BASE RESOURCE to " + path);
}

//TODO think of better way of doing this
//pass through properties as attributes directly
Expand Down Expand Up @@ -356,28 +362,77 @@ public ContextHandler createContextHandler(final App app) throws Exception
if (contextHandlerClassName != null)
context = Class.forName(contextHandlerClassName).getDeclaredConstructor().newInstance();

//add in environment-specific properties
//Add in environment-specific properties:
// allow multiple eeXX[-zzz].properties files, ordered lexically
// allow each to contain jetty.deploy.environmentXml[.zzzz] properties
// accumulate all properties for substitution purposes
// order all jetty.deploy.environmentXml[.zzzz] properties lexically
// apply the context xml files named by the ordered jetty.deploy.environmentXml[.zzzz] properties
String env = app.getEnvironmentName() == null ? "" : app.getEnvironmentName();
Path envProperties = app.getPath().getParent().resolve(env + ".properties");
if (Files.exists(envProperties))

List<Path> envPropertyFiles = new ArrayList<>();
Path parent = app.getPath().getParent();

//Get all environment specific properties files for this environment,
//order them according to the lexical ordering of the filenames
try (Stream<Path> paths = Files.list(parent))
{
try (InputStream stream = Files.newInputStream(envProperties))
{
Properties p = new Properties();
p.load(stream);
p.stringPropertyNames().forEach(k -> properties.put(k, p.getProperty(k)));
}
envPropertyFiles = paths.filter(Files::isRegularFile)
.map(p -> parent.relativize(p))
.filter(p ->
{
String name = p.getName(0).toString();
if (!name.endsWith(".properties"))
return false;
if (!name.startsWith(env))
janbartel marked this conversation as resolved.
Show resolved Hide resolved
return false;
return true;
}).sorted().collect(Collectors.toList());
}

String str = properties.get(Deployable.ENVIRONMENT_XML);
if (!StringUtil.isEmpty(str))
{
Path envXmlPath = Paths.get(str);
if (!envXmlPath.isAbsolute())
envXmlPath = getMonitoredDirResource().getPath().getParent().resolve(envXmlPath);
if (LOG.isDebugEnabled())
LOG.debug("Environment property files {}", envPropertyFiles);

context = applyXml(context, envXmlPath, env, properties);
Map<String, Path> envXmlFilenameMap = new HashMap<>();
for (Path file : envPropertyFiles)
{
Path resolvedFile = parent.resolve(file);
if (Files.exists(resolvedFile))
{
Properties tmp = new Properties();
try (InputStream stream = Files.newInputStream(resolvedFile))
Copy link
Contributor

Choose a reason for hiding this comment

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

Aren't these meant to be merged into the single properties file and then that is checed properties with the prefix?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't understand your question, if you look at lines 406 and 407 the properties are all added into the general property substitution pool:

                    try (InputStream stream = Files.newInputStream(resolvedFile))
                    {
                        tmp.load(stream);
                        //put each property into our substitution pool
                        tmp.stringPropertyNames().forEach(k -> properties.put(k, tmp.getProperty(k)));

{
tmp.load(stream);
//put each property into our substitution pool
tmp.stringPropertyNames().forEach(k -> properties.put(k, tmp.getProperty(k)));
//extract any properties that name environment context xml files
for (Map.Entry<Object, Object> entry : tmp.entrySet())
{
String name = Objects.toString(entry.getKey(), "");
if (name.startsWith(Deployable.ENVIRONMENT_XML))
{
//ensure all environment context xml files are absolute paths
Path envXmlPath = Paths.get(entry.getValue().toString());
if (!envXmlPath.isAbsolute())
envXmlPath = getMonitoredDirResource().getPath().getParent().resolve(envXmlPath);
//accumulate all properties that name environment xml files so they can be ordered
envXmlFilenameMap.put(name, envXmlPath);
}
}
janbartel marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
//order the environment context xml files according to the name of their properties
List<String> sortedEnvXmlProperties = envXmlFilenameMap.keySet().stream().sorted().toList();

//apply each environment context xml file
for (String property : sortedEnvXmlProperties)
{
Path envXmlPath = envXmlFilenameMap.get(property);
if (LOG.isDebugEnabled())
LOG.debug("Applying environment specific context file {}", envXmlPath);
context = applyXml(context, envXmlPath, env, properties);
}

//add in properties specific to the deployable
properties.putAll(app.getProperties());
Expand Down Expand Up @@ -427,9 +482,10 @@ else if (!Files.isDirectory(path) && !FileID.isWebArchive(path))
throw new IllegalStateException("Unknown ContextHandler class " + contextHandlerClassName + " for " + app);

context = contextHandlerClass.getDeclaredConstructor().newInstance();
properties.put(Deployable.WAR, path.toString());
}

//set a backup value for the path to the war in case it hasn't already been set
properties.put(Deployable.WAR, path.toString());
return initializeContextHandler(context, path, properties);
}
finally
Expand Down
Loading
Loading