* Issue #11847 implement environment context xml
This commit is contained in:
parent
95059356c9
commit
6ee17f002c
|
@ -21,6 +21,7 @@ import java.net.URL;
|
|||
import java.net.URLClassLoader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
@ -77,8 +78,8 @@ import org.slf4j.LoggerFactory;
|
|||
* <p>For XML configured contexts, the ID map will contain a reference to the {@link Server} instance called "Server" and
|
||||
* properties for the webapp file such as "jetty.webapp" and directory as "jetty.webapps".
|
||||
* The properties will be initialized with:<ul>
|
||||
* <li>The properties set on the application via {@link App#getProperties()}; otherwise:</li>
|
||||
* <li>The properties set on this provider via {@link #getProperties()}</li>
|
||||
* <li>The properties set on the application via {@link App#getProperties()}; otherwise:</li>
|
||||
* <li>The properties set on this provider via {@link #getProperties()}</li>
|
||||
* </ul>
|
||||
*/
|
||||
@ManagedObject("Provider for start-up deployment of webapps based on presence in directory")
|
||||
|
@ -243,6 +244,7 @@ public class ContextProvider extends ScanningAppProvider
|
|||
|
||||
/**
|
||||
* This is equivalent to setting the {@link Deployable#CONFIGURATION_CLASSES} property.
|
||||
*
|
||||
* @param configurations The configuration class names as a comma separated list
|
||||
*/
|
||||
public void setConfigurationClasses(String configurations)
|
||||
|
@ -252,6 +254,7 @@ public class ContextProvider extends ScanningAppProvider
|
|||
|
||||
/**
|
||||
* This is equivalent to setting the {@link Deployable#CONFIGURATION_CLASSES} property.
|
||||
*
|
||||
* @param configurations The configuration class names.
|
||||
*/
|
||||
public void setConfigurationClasses(String[] configurations)
|
||||
|
@ -262,8 +265,8 @@ public class ContextProvider extends ScanningAppProvider
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* This is equivalent to getting the {@link Deployable#CONFIGURATION_CLASSES} property.
|
||||
*
|
||||
* @return The configuration class names.
|
||||
*/
|
||||
@ManagedAttribute("configuration classes for webapps to be processed through")
|
||||
|
@ -341,32 +344,48 @@ public class ContextProvider extends ScanningAppProvider
|
|||
|
||||
// prepare properties
|
||||
Map<String, String> properties = new HashMap<>();
|
||||
|
||||
//add in properties from start mechanism
|
||||
properties.putAll(getProperties());
|
||||
|
||||
Object context = null;
|
||||
//check if there is a specific ContextHandler type to create set in the
|
||||
//properties associated with the webapp. If there is, we create it _before_
|
||||
//applying the environment xml file.
|
||||
String contextHandlerClassName = app.getProperties().get(Deployable.CONTEXT_HANDLER_CLASS);
|
||||
if (contextHandlerClassName != null)
|
||||
context = Class.forName(contextHandlerClassName).getDeclaredConstructor().newInstance();
|
||||
|
||||
//add in environment-specific properties
|
||||
String env = app.getEnvironmentName() == null ? "" : app.getEnvironmentName();
|
||||
Path envProperties = app.getPath().getParent().resolve(env + ".properties");
|
||||
if (Files.exists(envProperties))
|
||||
{
|
||||
try (InputStream stream = Files.newInputStream(envProperties))
|
||||
{
|
||||
Properties p = new Properties();
|
||||
p.load(stream);
|
||||
p.stringPropertyNames().forEach(k -> properties.put(k, p.getProperty(k)));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
context = applyXml(context, envXmlPath, env, properties);
|
||||
}
|
||||
}
|
||||
|
||||
//add in properties specific to the deployable
|
||||
properties.putAll(app.getProperties());
|
||||
|
||||
// Handle a context XML file
|
||||
if (FileID.isXml(path))
|
||||
{
|
||||
XmlConfiguration xmlc = new XmlConfiguration(ResourceFactory.of(this).newResource(path), null, properties)
|
||||
{
|
||||
@Override
|
||||
public void initializeDefaults(Object context)
|
||||
{
|
||||
super.initializeDefaults(context);
|
||||
ContextProvider.this.initializeContextHandler(context, path, properties);
|
||||
}
|
||||
};
|
||||
|
||||
xmlc.getIdMap().put("Environment", environment);
|
||||
xmlc.setJettyStandardIdsAndProperties(getDeploymentManager().getServer(), path);
|
||||
|
||||
// If it is a core context environment, then look for a classloader
|
||||
ClassLoader coreContextClassLoader = Environment.CORE.equals(environment) ? findCoreContextClassLoader(path) : null;
|
||||
if (coreContextClassLoader != null)
|
||||
Thread.currentThread().setContextClassLoader(coreContextClassLoader);
|
||||
|
||||
// Create the context by running the configuration
|
||||
Object context = xmlc.configure();
|
||||
context = applyXml(context, path, env, properties);
|
||||
|
||||
// Look for the contextHandler itself
|
||||
ContextHandler contextHandler = null;
|
||||
|
@ -382,27 +401,33 @@ public class ContextProvider extends ScanningAppProvider
|
|||
throw new IllegalStateException("Unknown context type of " + context);
|
||||
|
||||
// Set the classloader if we have a coreContextClassLoader
|
||||
ClassLoader coreContextClassLoader = Environment.CORE.equals(environment) ? findCoreContextClassLoader(path) : null;
|
||||
if (coreContextClassLoader != null)
|
||||
contextHandler.setClassLoader(coreContextClassLoader);
|
||||
|
||||
return contextHandler;
|
||||
}
|
||||
|
||||
// Otherwise it must be a directory or an archive
|
||||
else if (!Files.isDirectory(path) && !FileID.isWebArchive(path))
|
||||
{
|
||||
throw new IllegalStateException("unable to create ContextHandler for " + app);
|
||||
}
|
||||
|
||||
// Build the web application
|
||||
String contextHandlerClassName = (String)environment.getAttribute("contextHandlerClass");
|
||||
if (StringUtil.isBlank(contextHandlerClassName))
|
||||
throw new IllegalStateException("No ContextHandler classname for " + app);
|
||||
Class<?> contextHandlerClass = Loader.loadClass(contextHandlerClassName);
|
||||
if (contextHandlerClass == null)
|
||||
throw new IllegalStateException("Unknown ContextHandler class " + contextHandlerClassName + " for " + app);
|
||||
// Build the web application if necessary
|
||||
if (context == null)
|
||||
{
|
||||
contextHandlerClassName = (String)environment.getAttribute("contextHandlerClass");
|
||||
if (StringUtil.isBlank(contextHandlerClassName))
|
||||
throw new IllegalStateException("No ContextHandler classname for " + app);
|
||||
Class<?> contextHandlerClass = Loader.loadClass(contextHandlerClassName);
|
||||
if (contextHandlerClass == null)
|
||||
throw new IllegalStateException("Unknown ContextHandler class " + contextHandlerClassName + " for " + app);
|
||||
|
||||
context = contextHandlerClass.getDeclaredConstructor().newInstance();
|
||||
properties.put(Deployable.WAR, path.toString());
|
||||
}
|
||||
|
||||
Object context = contextHandlerClass.getDeclaredConstructor().newInstance();
|
||||
properties.put(Deployable.WAR, path.toString());
|
||||
return initializeContextHandler(context, path, properties);
|
||||
}
|
||||
finally
|
||||
|
@ -411,6 +436,36 @@ public class ContextProvider extends ScanningAppProvider
|
|||
}
|
||||
}
|
||||
|
||||
protected Object applyXml(Object context, Path xml, String environment, Map<String, String> properties) throws Exception
|
||||
{
|
||||
if (!FileID.isXml(xml))
|
||||
return null;
|
||||
|
||||
XmlConfiguration xmlc = new XmlConfiguration(ResourceFactory.of(this).newResource(xml), null, properties)
|
||||
{
|
||||
@Override
|
||||
public void initializeDefaults(Object context)
|
||||
{
|
||||
super.initializeDefaults(context);
|
||||
ContextProvider.this.initializeContextHandler(context, xml, properties);
|
||||
}
|
||||
};
|
||||
|
||||
xmlc.getIdMap().put("Environment", environment);
|
||||
xmlc.setJettyStandardIdsAndProperties(getDeploymentManager().getServer(), xml);
|
||||
|
||||
// If it is a core context environment, then look for a classloader
|
||||
ClassLoader coreContextClassLoader = Environment.CORE.equals(environment) ? findCoreContextClassLoader(xml) : null;
|
||||
if (coreContextClassLoader != null)
|
||||
Thread.currentThread().setContextClassLoader(coreContextClassLoader);
|
||||
|
||||
// Create or configure the context
|
||||
if (context == null)
|
||||
return xmlc.configure();
|
||||
|
||||
return xmlc.configure(context);
|
||||
}
|
||||
|
||||
protected ClassLoader findCoreContextClassLoader(Path path) throws IOException
|
||||
{
|
||||
Path webapps = path.getParent();
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.deploy;
|
||||
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
|
||||
public class BarContextHandler extends ContextHandler
|
||||
{
|
||||
}
|
|
@ -15,27 +15,18 @@ package org.eclipse.jetty.deploy.providers;
|
|||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingDeque;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
|
||||
import org.eclipse.jetty.deploy.AppProvider;
|
||||
import org.eclipse.jetty.deploy.DeploymentManager;
|
||||
import org.eclipse.jetty.deploy.BarContextHandler;
|
||||
import org.eclipse.jetty.deploy.test.XmlConfiguredJetty;
|
||||
import org.eclipse.jetty.server.Handler;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.Deployable;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.toolchain.test.FS;
|
||||
import org.eclipse.jetty.toolchain.test.MavenPaths;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||
import org.eclipse.jetty.util.Scanner;
|
||||
import org.eclipse.jetty.util.component.Container;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -43,6 +34,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
|||
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
@ -77,7 +69,10 @@ public class ContextProviderStartupTest
|
|||
|
||||
// Should not throw an Exception
|
||||
jetty.load();
|
||||
}
|
||||
|
||||
public void startJetty() throws Exception
|
||||
{
|
||||
// Start it
|
||||
jetty.start();
|
||||
}
|
||||
|
@ -89,9 +84,47 @@ public class ContextProviderStartupTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testStartupContext()
|
||||
public void testStartupContext() throws Exception
|
||||
{
|
||||
startJetty();
|
||||
|
||||
// Check Server for Handlers
|
||||
jetty.assertContextHandlerExists("/bar");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartupWithRelativeEnvironmentContext() throws Exception
|
||||
{
|
||||
Path jettyBase = jetty.getJettyBasePath();
|
||||
Path propsFile = Files.writeString(jettyBase.resolve("webapps/core.properties"), Deployable.ENVIRONMENT_XML + " = etc/core-context.xml", StandardOpenOption.CREATE_NEW);
|
||||
assertTrue(Files.exists(propsFile));
|
||||
Files.copy(MavenPaths.findTestResourceFile("etc/core-context.xml"), jettyBase.resolve("etc/core-context.xml"), StandardCopyOption.REPLACE_EXISTING);
|
||||
jetty.copyWebapp("bar-core-context.properties", "bar.properties");
|
||||
startJetty();
|
||||
|
||||
//check environment context xml was applied to the produced context
|
||||
ContextHandler context = jetty.getContextHandler("/bar");
|
||||
assertNotNull(context);
|
||||
assertThat(context.getAttribute("somename"), equalTo("somevalue"));
|
||||
assertTrue(context instanceof BarContextHandler);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStartupWithAbsoluteEnvironmentContext() throws Exception
|
||||
{
|
||||
Path jettyBase = jetty.getJettyBasePath();
|
||||
Path propsFile = Files.writeString(jettyBase.resolve("webapps/core.properties"), Deployable.ENVIRONMENT_XML + " = " +
|
||||
MavenPaths.findTestResourceFile("etc/core-context.xml"), StandardOpenOption.CREATE_NEW);
|
||||
assertTrue(Files.exists(propsFile));
|
||||
Files.copy(MavenPaths.findTestResourceFile("etc/core-context.xml"), jettyBase.resolve("etc/core-context.xml"), StandardCopyOption.REPLACE_EXISTING);
|
||||
jetty.copyWebapp("bar-core-context.properties", "bar-core-context.properties");
|
||||
startJetty();
|
||||
|
||||
//check environment context xml was applied to the produced context
|
||||
ContextHandler context = jetty.getContextHandler("/bar");
|
||||
assertNotNull(context);
|
||||
assertThat(context.getAttribute("somename"), equalTo("somevalue"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!-- // -->
|
||||
<!-- // ======================================================================== -->
|
||||
<!-- // 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 -->
|
||||
<!-- // ======================================================================== -->
|
||||
<!-- // -->
|
||||
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://eclipse.dev/jetty/configure_10_0.dtd">
|
||||
<Configure class="org.eclipse.jetty.server.handler.ContextHandler">
|
||||
<Set name="contextPath">/global</Set>
|
||||
<Call name="setAttribute">
|
||||
<Arg>somename</Arg>
|
||||
<Arg>somevalue</Arg>
|
||||
</Call>
|
||||
</Configure>
|
|
@ -0,0 +1,2 @@
|
|||
environment: core
|
||||
jetty.deploy.contextHandlerClass: org.eclipse.jetty.deploy.BarContextHandler
|
|
@ -56,8 +56,10 @@ public interface Deployable
|
|||
String CONFIGURATION_CLASSES = "jetty.deploy.configurationClasses";
|
||||
String CONTAINER_SCAN_JARS = "jetty.deploy.containerScanJarPattern";
|
||||
String CONTEXT_PATH = "jetty.deploy.contextPath";
|
||||
String CONTEXT_HANDLER_CLASS = "jetty.deploy.contextHandlerClass";
|
||||
String DEFAULTS_DESCRIPTOR = "jetty.deploy.defaultsDescriptor";
|
||||
String ENVIRONMENT = "environment";
|
||||
String ENVIRONMENT_XML = "jetty.deploy.environmentXml";
|
||||
String EXTRACT_WARS = "jetty.deploy.extractWars";
|
||||
String PARENT_LOADER_PRIORITY = "jetty.deploy.parentLoaderPriority";
|
||||
String SCI_EXCLUSION_PATTERN = "jetty.deploy.servletContainerInitializerExclusionPattern";
|
||||
|
|
Loading…
Reference in New Issue