WIP for deployer
This commit is contained in:
parent
3f6f725cce
commit
85af234ed6
|
@ -24,7 +24,7 @@ public class App
|
|||
private final DeploymentManager _manager;
|
||||
private final AppProvider _provider;
|
||||
private final String _environment;
|
||||
private final String _originId;
|
||||
private final String _filename;
|
||||
private ContextHandler _context;
|
||||
|
||||
/**
|
||||
|
@ -33,17 +33,16 @@ public class App
|
|||
* @param manager the deployment manager
|
||||
* @param provider the app provider
|
||||
* @param environment the name of the environment or null for the server environment.
|
||||
* @param originId the origin ID (The ID that the {@link AppProvider} knows
|
||||
* about)
|
||||
* @see App#getOriginId()
|
||||
* @param filename the filename of the base resource of the application
|
||||
* @see App#getFilename()
|
||||
* @see App#getContextPath()
|
||||
*/
|
||||
public App(DeploymentManager manager, AppProvider provider, String environment, String originId)
|
||||
public App(DeploymentManager manager, AppProvider provider, String environment, String filename)
|
||||
{
|
||||
_manager = manager;
|
||||
_provider = provider;
|
||||
_environment = environment;
|
||||
_originId = originId;
|
||||
_filename = filename;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -128,14 +127,14 @@ public class App
|
|||
*
|
||||
* @return String representing the origin of this app.
|
||||
*/
|
||||
public String getOriginId()
|
||||
public String getFilename()
|
||||
{
|
||||
return this._originId;
|
||||
return this._filename;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "App[" + _context + "," + _originId + "]";
|
||||
return "App[" + _context + "," + _filename + "]";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -140,7 +140,7 @@ public class DeploymentManager extends ContainerLifeCycle
|
|||
*/
|
||||
public void addApp(App app)
|
||||
{
|
||||
LOG.debug("Deployable added: {}", app.getOriginId());
|
||||
LOG.debug("Deployable added: {}", app.getFilename());
|
||||
AppEntry entry = new AppEntry();
|
||||
entry.app = app;
|
||||
entry.setLifeCycleNode(_lifecycle.getNodeByName("undeployed"));
|
||||
|
@ -293,7 +293,7 @@ public class DeploymentManager extends ContainerLifeCycle
|
|||
|
||||
for (AppEntry entry : _apps)
|
||||
{
|
||||
if (originId.equals(entry.app.getOriginId()))
|
||||
if (originId.equals(entry.app.getFilename()))
|
||||
{
|
||||
return entry;
|
||||
}
|
||||
|
@ -480,7 +480,7 @@ public class DeploymentManager extends ContainerLifeCycle
|
|||
*/
|
||||
public void requestAppGoal(App app, String nodeName)
|
||||
{
|
||||
AppEntry appentry = findAppByOriginId(app.getOriginId());
|
||||
AppEntry appentry = findAppByOriginId(app.getFilename());
|
||||
if (appentry == null)
|
||||
{
|
||||
throw new IllegalStateException("App not being tracked by Deployment Manager: " + app);
|
||||
|
|
|
@ -79,7 +79,7 @@ public class DeploymentManagerMBean extends ObjectMBean
|
|||
|
||||
private String toRef(App app)
|
||||
{
|
||||
return String.format("originId=%s,contextPath=%s,appProvider=%s", app.getContextPath(), app.getOriginId(), app.getAppProvider().getClass().getName());
|
||||
return String.format("originId=%s,contextPath=%s,appProvider=%s", app.getContextPath(), app.getFilename(), app.getAppProvider().getClass().getName());
|
||||
}
|
||||
|
||||
public Collection<ContextHandler> getContexts() throws Exception
|
||||
|
|
|
@ -15,6 +15,10 @@ package org.eclipse.jetty.deploy.providers;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.FilenameFilter;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
||||
|
@ -23,11 +27,13 @@ import org.eclipse.jetty.deploy.ConfigurationManager;
|
|||
import org.eclipse.jetty.deploy.util.FileID;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.component.Environment;
|
||||
import org.eclipse.jetty.util.resource.JarResource;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.xml.XmlConfiguration;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -58,11 +64,11 @@ import org.slf4j.LoggerFactory;
|
|||
* properties for the webapp file as "jetty.webapp" and directory as "jetty.webapps".
|
||||
*/
|
||||
@ManagedObject("Provider for start-up deployement of webapps based on presence in directory")
|
||||
public class WebAppProvider extends ScanningAppProvider
|
||||
public class ContextProvider extends ScanningAppProvider
|
||||
{
|
||||
private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(WebAppProvider.class);
|
||||
private static final org.slf4j.Logger LOG = LoggerFactory.getLogger(ContextProvider.class);
|
||||
|
||||
private boolean _extractWars = false;
|
||||
private boolean _extract = false;
|
||||
private boolean _parentLoaderPriority = false;
|
||||
private ConfigurationManager _configurationManager;
|
||||
private String _defaultsDescriptor;
|
||||
|
@ -115,7 +121,7 @@ public class WebAppProvider extends ScanningAppProvider
|
|||
}
|
||||
}
|
||||
|
||||
public WebAppProvider()
|
||||
public ContextProvider()
|
||||
{
|
||||
super();
|
||||
setFilenameFilter(new Filter());
|
||||
|
@ -126,21 +132,43 @@ public class WebAppProvider extends ScanningAppProvider
|
|||
* Get the extractWars.
|
||||
*
|
||||
* @return the extractWars
|
||||
* @deprecated use {@link #isExtract()}
|
||||
*/
|
||||
@ManagedAttribute("extract war files")
|
||||
@Deprecated
|
||||
public boolean isExtractWars()
|
||||
{
|
||||
return _extractWars;
|
||||
return isExtract();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if WAR and JAR are extraced on deploy.
|
||||
*/
|
||||
@ManagedAttribute("extract WAR and JAR files")
|
||||
public boolean isExtract()
|
||||
{
|
||||
return _extract;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the extractWars.
|
||||
*
|
||||
* @param extractWars the extractWars to set
|
||||
* @param extract the extractWars to set
|
||||
* @deprecated use {@link #setExtract(boolean)}
|
||||
*/
|
||||
public void setExtractWars(boolean extractWars)
|
||||
@Deprecated
|
||||
public void setExtractWars(boolean extract)
|
||||
{
|
||||
_extractWars = extractWars;
|
||||
setExtract(extract);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to extract WAR and JAR files.
|
||||
*
|
||||
* @param extract the extractWars to set
|
||||
*/
|
||||
public void setExtract(boolean extract)
|
||||
{
|
||||
_extract = extract;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -248,6 +276,8 @@ public class WebAppProvider extends ScanningAppProvider
|
|||
if (_configurationClasses != null)
|
||||
webapp.setConfigurationClasses(_configurationClasses);
|
||||
|
||||
*/
|
||||
|
||||
if (_tempDirectory != null)
|
||||
{
|
||||
// Since the Temp Dir is really a context base temp directory,
|
||||
|
@ -255,9 +285,8 @@ public class WebAppProvider extends ScanningAppProvider
|
|||
// instead of setting the WebAppContext.setTempDirectory(File).
|
||||
// If we used .setTempDirectory(File) all webapps will wind up in the
|
||||
// same temp / work directory, overwriting each others work.
|
||||
webapp.setAttribute(WebAppContext.BASETEMPDIR, _tempDirectory);
|
||||
webapp.setAttribute(Server.BASE_TEMP_DIR_ATTR, _tempDirectory);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -273,10 +302,13 @@ public class WebAppProvider extends ScanningAppProvider
|
|||
{
|
||||
Thread.currentThread().setContextClassLoader(environment.getClassLoader());
|
||||
|
||||
Resource resource = Resource.newResource(app.getOriginId());
|
||||
File file = resource.getFile();
|
||||
Resource resource = Resource.newResource(app.getFilename());
|
||||
if (!resource.exists())
|
||||
throw new IllegalStateException("App resource does not exist " + resource);
|
||||
resource = unpack(resource);
|
||||
|
||||
File file = resource.getFile();
|
||||
|
||||
|
||||
final String contextName = file.getName();
|
||||
|
||||
|
@ -322,12 +354,16 @@ public class WebAppProvider extends ScanningAppProvider
|
|||
}
|
||||
|
||||
// Build the web application
|
||||
ContextHandler webAppContext = null; // TODO new WebAppContext();
|
||||
webAppContext.setBaseResource(Resource.newResource(file.getAbsoluteFile()));
|
||||
initializeContextPath(webAppContext, contextName, !file.isDirectory());
|
||||
initializeWebAppContextDefaults(webAppContext);
|
||||
@SuppressWarnings("unchecked")
|
||||
Class<? extends ContextHandler> contextHandlerClass = (Class<? extends ContextHandler>)environment.getAttribute("contextHandlerClass");
|
||||
if (contextHandlerClass == null)
|
||||
throw new IllegalStateException("Unknown ContextHandler class for " + app);
|
||||
ContextHandler contextHandler = contextHandlerClass.getDeclaredConstructor().newInstance();
|
||||
contextHandler.setBaseResource(Resource.newResource(file.getAbsoluteFile()));
|
||||
initializeContextPath(contextHandler, contextName, !file.isDirectory());
|
||||
initializeWebAppContextDefaults(contextHandler);
|
||||
|
||||
return webAppContext;
|
||||
return contextHandler;
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -446,6 +482,10 @@ public class WebAppProvider extends ScanningAppProvider
|
|||
if (exists(file.getName() + ".war") || exists(file.getName() + ".WAR"))
|
||||
return; //assume we will get added events for the war file
|
||||
|
||||
//is there .jar file of the same name?
|
||||
if (exists(file.getName() + ".jar") || exists(file.getName() + ".JAR"))
|
||||
return; //assume we will get added events for the jar file
|
||||
|
||||
super.fileAdded(filename);
|
||||
return;
|
||||
}
|
||||
|
@ -505,4 +545,90 @@ public class WebAppProvider extends ScanningAppProvider
|
|||
|
||||
super.fileRemoved(filename);
|
||||
}
|
||||
|
||||
public Resource unpack(Resource resourceBase) throws IOException
|
||||
{
|
||||
// Accept aliases for WAR files
|
||||
if (resourceBase.isAlias())
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} anti-aliased to {}", resourceBase, resourceBase.getAlias());
|
||||
URI alias = resourceBase.getAlias();
|
||||
resourceBase.close();
|
||||
resourceBase = Resource.newResource(alias);
|
||||
}
|
||||
|
||||
if (!isExtract() || resourceBase.isDirectory() || resourceBase.getFile() == null)
|
||||
return resourceBase;
|
||||
|
||||
// is the extension a known extension
|
||||
if (!resourceBase.getFile().getName().toLowerCase().endsWith(".war") &&
|
||||
!resourceBase.getFile().getName().toLowerCase().endsWith(".jar"))
|
||||
return resourceBase;
|
||||
|
||||
// Track the original web_app Resource, as this could be a PathResource.
|
||||
// Later steps force the Resource to be a JarFileResource, which introduces
|
||||
// URLConnection caches in such a way that it prevents Hot Redeployment
|
||||
// on MS Windows.
|
||||
Resource originalResource = resourceBase;
|
||||
|
||||
// Look for unpacked directory
|
||||
Path path = resourceBase.getPath();
|
||||
String name = path.getName(path.getNameCount() - 1).toString();
|
||||
name = name.substring(0, name.length() - 4);
|
||||
Path directory = path.getParent(); // TODO support unpacking to temp or work directory
|
||||
File unpacked = directory.resolve(name).toFile();
|
||||
File extractLock = directory.resolve(".extract_lock").toFile();
|
||||
|
||||
if (!Files.isWritable(directory))
|
||||
{
|
||||
LOG.warn("!Writable {} -> {}", resourceBase, directory);
|
||||
return resourceBase;
|
||||
}
|
||||
|
||||
// Does the directory already exist and is newer than the packed file?
|
||||
if (unpacked.exists())
|
||||
{
|
||||
// If it is not a directory, then we can't unpack
|
||||
if (!unpacked.isDirectory())
|
||||
{
|
||||
LOG.warn("Unusable {} -> {}", resourceBase, unpacked);
|
||||
return resourceBase;
|
||||
}
|
||||
|
||||
// If it is newer than the resource base and there is no partial extraction, then use it.
|
||||
if (Files.getLastModifiedTime(directory).toMillis() >= resourceBase.lastModified() && !extractLock.exists())
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Reuse {} -> {}", resourceBase, unpacked);
|
||||
resourceBase.close();
|
||||
return Resource.newResource(unpacked);
|
||||
}
|
||||
|
||||
extractLock.createNewFile();
|
||||
IO.delete(unpacked);
|
||||
}
|
||||
else
|
||||
{
|
||||
extractLock.createNewFile();
|
||||
}
|
||||
|
||||
if (!unpacked.mkdir())
|
||||
{
|
||||
LOG.warn("Cannot Create {} -> {}", resourceBase, unpacked);
|
||||
extractLock.delete();
|
||||
return resourceBase;
|
||||
}
|
||||
|
||||
LOG.debug("Unpack {} -> {}", resourceBase, unpacked);
|
||||
try (Resource jar = JarResource.newJarResource(resourceBase))
|
||||
{
|
||||
jar.copyTo(unpacked);
|
||||
}
|
||||
|
||||
extractLock.delete();
|
||||
resourceBase.close();
|
||||
|
||||
return Resource.newResource(unpacked);
|
||||
}
|
||||
}
|
|
@ -58,7 +58,7 @@ public class DeploymentManagerTest
|
|||
// Test app get
|
||||
App actual = depman.getAppByOriginId("mock-foo-webapp-1.war");
|
||||
assertNotNull(actual, "Should have gotten app (by id)");
|
||||
assertEquals("mock-foo-webapp-1.war", actual.getOriginId(), "Should have gotten app (by id)");
|
||||
assertEquals("mock-foo-webapp-1.war", actual.getFilename(), "Should have gotten app (by id)");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -49,7 +49,7 @@ public class MockAppProvider extends AbstractLifeCycle implements AppProvider
|
|||
{
|
||||
ContextHandler contextHandler = new ContextHandler();
|
||||
|
||||
File war = new File(webappsDir, app.getOriginId().substring(5));
|
||||
File war = new File(webappsDir, app.getFilename().substring(5));
|
||||
|
||||
String path = war.getName();
|
||||
|
||||
|
|
|
@ -61,6 +61,7 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
public class Server extends Handler.Wrapper implements Attributes
|
||||
{
|
||||
public static final String BASE_TEMP_DIR_ATTR = "org.eclipse.jetty.server.BaseTempDir";
|
||||
private static final Logger LOG = LoggerFactory.getLogger(Server.class);
|
||||
private static final String __serverInfo = "jetty/" + Server.getVersion();
|
||||
|
||||
|
|
|
@ -47,13 +47,11 @@ import org.eclipse.jetty.ee10.servlet.security.ConstraintAware;
|
|||
import org.eclipse.jetty.ee10.servlet.security.ConstraintMapping;
|
||||
import org.eclipse.jetty.ee10.servlet.security.ConstraintSecurityHandler;
|
||||
import org.eclipse.jetty.ee10.servlet.security.SecurityHandler;
|
||||
import org.eclipse.jetty.http.MimeTypes;
|
||||
import org.eclipse.jetty.server.ClassLoaderDump;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.util.MultiException;
|
||||
import org.eclipse.jetty.util.TopologicalSort;
|
||||
import org.eclipse.jetty.util.URIUtil;
|
||||
import org.eclipse.jetty.util.annotation.ManagedAttribute;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
|
@ -74,73 +72,6 @@ import org.slf4j.LoggerFactory;
|
|||
* the default being {@link WebXmlConfiguration} and
|
||||
* {@link JettyWebXmlConfiguration}.
|
||||
*
|
||||
*
|
||||
* <p>
|
||||
* The Start/Configuration of a WebAppContext is rather complex so as to allow
|
||||
* pluggable behaviour to be added in almost arbitrary ordering. The
|
||||
* sequence of a WebappContext start is as follows:
|
||||
* <blockquote>
|
||||
* {@link #doStart()}:
|
||||
* <ul>
|
||||
* <li>{@link #preConfigure()}
|
||||
* <ul>
|
||||
* <li>Add all Server class inclusions from all known configurations {@link Configurations#getKnown()}</li>
|
||||
* <li>{@link #loadConfigurations()}, which uses either explicitly set Configurations or takes the server
|
||||
* default (which is all known {@link Configuration#isEnabledByDefault()} Configurations.</li>
|
||||
* <li>Sort the configurations using {@link TopologicalSort} in {@link Configurations#sort()}.</li>
|
||||
* <li>Add all Server class exclusions from this webapps {@link Configurations}</li>
|
||||
* <li>Add all System classes inclusions and exclusions for this webapps {@link Configurations}</li>
|
||||
* <li>Instantiate the WebAppClassLoader (if one not already explicitly set)</li>
|
||||
* <li>{@link Configuration#preConfigure(WebAppContext)} which calls
|
||||
* {@link Configuration#preConfigure(WebAppContext)} for this webapps {@link Configurations}</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* <li>{@link ServletContextHandler#doStart()}
|
||||
* <ul>
|
||||
* <li>{@link org.eclipse.jetty.server.handler.ContextHandler#doStart()}
|
||||
* <ul>
|
||||
* <li>Init {@link MimeTypes}</li>
|
||||
* <li>enterScope
|
||||
* <ul>
|
||||
* <li>{@link #startContext()}
|
||||
* <ul>
|
||||
* <li>{@link #configure()}
|
||||
* <ul>
|
||||
* <li>Call {@link Configuration#configure(WebAppContext)} on enabled {@link Configurations}</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* <li>{@link MetaData#resolve(WebAppContext)}</li>
|
||||
* <li>{@link #startContext()}
|
||||
* <li>QuickStart may generate here and/or abort start
|
||||
* <ul>
|
||||
* <li>{@link ServletContextHandler#startContext}
|
||||
* <ul>
|
||||
* <li>Decorate listeners</li>
|
||||
* <li>{@link org.eclipse.jetty.server.handler.ContextHandler#startContext}
|
||||
* <ul>
|
||||
* <li>add {@link org.eclipse.jetty.ee10.servlet.ManagedAttributeListener}</li>
|
||||
* <li>{@link AbstractHandler#doStart}</li>
|
||||
* <li>{@link #callContextInitialized(jakarta.servlet.ServletContextListener, jakarta.servlet.ServletContextEvent)}</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* <li>{@link ServletHandler#initialize()}</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* <li>exitScope</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* <li>{@link #postConfigure()}</li>
|
||||
* </ul>
|
||||
*
|
||||
* </blockquote>
|
||||
*/
|
||||
@ManagedObject("Web Application ContextHandler")
|
||||
public class WebAppContext extends ServletContextHandler implements WebAppClassLoader.Context
|
||||
|
@ -148,7 +79,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
|||
static final Logger LOG = LoggerFactory.getLogger(WebAppContext.class);
|
||||
|
||||
public static final String TEMPDIR = ServletContext.TEMPDIR;
|
||||
public static final String BASETEMPDIR = "org.eclipse.jetty.webapp.basetempdir";
|
||||
public static final String BASETEMPDIR = Server.BASE_TEMP_DIR_ATTR;
|
||||
public static final String WEB_DEFAULTS_XML = "org/eclipse/jetty/ee10/webapp/webdefault.xml";
|
||||
public static final String ERROR_PAGE = "org.eclipse.jetty.server.error_page";
|
||||
public static final String SERVER_SYS_CLASSES = "org.eclipse.jetty.webapp.systemClasses";
|
||||
|
|
|
@ -131,7 +131,7 @@ public class WebInfConfiguration extends AbstractConfiguration
|
|||
* B. Create a directory based on global settings. The new directory
|
||||
* will be called <code>"Jetty-"+host+"-"+port+"__"+context+"-"+virtualhost+"-"+randomdigits+".dir"</code>
|
||||
* <p>
|
||||
* If the user has specified the context attribute org.eclipse.jetty.webapp.basetempdir, the
|
||||
* If the user has specified the context attribute {@link Server#BASE_TEMP_DIR_ATTR}, the
|
||||
* directory specified by this attribute will be the parent of the temp dir created. Otherwise,
|
||||
* the parent dir is <code>${java.io.tmpdir}</code>. Set delete on exit depends on value of persistTempDirectory.
|
||||
*
|
||||
|
|
Loading…
Reference in New Issue