298667 various deployer improvements

git-svn-id: svn+ssh://dev.eclipse.org/svnroot/rt/org.eclipse.jetty/jetty/trunk@1174 7e9141cc-0065-0410-87d8-b60c137991c4
This commit is contained in:
Greg Wilkins 2009-12-31 03:02:16 +00:00
parent 8e19d18057
commit 52fc378b93
16 changed files with 418 additions and 88 deletions

View File

@ -7,7 +7,7 @@ jetty-7.0.2-SNAPSHOT
+ 298144 Unit test for jetty-client connecting to a server that uses Basic Auth
+ 298145 Reorganized test harness to separate the HTTP PUT and HTTP GET test URLs
+ 298234 Unit test for jetty-client handling different HTTP error codes
+ 298667 DeploymentManager providers create ContextHandlers
+ 298667 DeploymentManager uses ContextProvider and WebAppProvider
+ JETTY-910 Allow request listeners to access session
+ JETTY-1155 HttpConnection.close notifies HttpExchange
+ JETTY-1156 SSL blocking close with JVM Bug busy key fix

View File

@ -18,7 +18,7 @@ import java.lang.management.ManagementFactory;
import org.eclipse.jetty.deploy.ContextDeployer;
import org.eclipse.jetty.deploy.DeploymentManager;
import org.eclipse.jetty.deploy.WebAppDeployer;
import org.eclipse.jetty.deploy.providers.ContextAppProvider;
import org.eclipse.jetty.deploy.providers.ContextProvider;
import org.eclipse.jetty.deploy.providers.WebAppProvider;
import org.eclipse.jetty.jmx.MBeanContainer;
import org.eclipse.jetty.security.HashLoginService;
@ -85,9 +85,9 @@ public class LikeJettyXml
deployer.setContexts(contexts);
server.addBean(deployer);
ContextAppProvider context_provider = new ContextAppProvider();
ContextProvider context_provider = new ContextProvider();
context_provider.setMonitoredDir(jetty_home + "/contexts");
context_provider.setScanInterval(5);
context_provider.setScanInterval(2);
server.addBean(context_provider);
deployer.addAppProvider(context_provider);
@ -95,7 +95,9 @@ public class LikeJettyXml
webapp_provider.setMonitoredDir(jetty_home + "/webapps");
webapp_provider.setParentLoaderPriority(false);
webapp_provider.setExtractWars(true);
webapp_provider.setScanInterval(2);
webapp_provider.setDefaultsDescriptor(jetty_home + "/etc/webdefault.xml");
webapp_provider.setContextXmlDir(jetty_home + "/contexts");
deployer.addAppProvider(webapp_provider);
HashLoginService login = new HashLoginService();

View File

@ -62,14 +62,16 @@ public class AppLifeCycle extends Graph
void processBinding(Node node, App app) throws Exception;
}
// Private string constants defined to avoid typos on repeatedly used strings
private static final String NODE_UNDEPLOYED = "undeployed";
private static final String NODE_DEPLOYING = "deploying";
private static final String NODE_DEPLOYED = "deployed";
private static final String NODE_STARTING = "starting";
private static final String NODE_STARTED = "started";
private static final String NODE_STOPPING = "stopping";
private static final String NODE_UNDEPLOYING = "undeploying";
// Well known existing lifecycle Nodes
public static final String UNDEPLOYED = "undeployed";
public static final String DEPLOYING = "deploying";
public static final String DEPLOYED = "deployed";
public static final String STARTING = "starting";
public static final String STARTED = "started";
public static final String STOPPING = "stopping";
public static final String UNDEPLOYING = "undeploying";
private Map<String, List<Binding>> lifecyclebindings = new HashMap<String, List<Binding>>();
public AppLifeCycle()
@ -77,20 +79,20 @@ public class AppLifeCycle extends Graph
// Define Default Graph
// undeployed -> deployed
addEdge(NODE_UNDEPLOYED,NODE_DEPLOYING);
addEdge(NODE_DEPLOYING,NODE_DEPLOYED);
addEdge(UNDEPLOYED,DEPLOYING);
addEdge(DEPLOYING,DEPLOYED);
// deployed -> started
addEdge(NODE_DEPLOYED,NODE_STARTING);
addEdge(NODE_STARTING,NODE_STARTED);
addEdge(DEPLOYED,STARTING);
addEdge(STARTING,STARTED);
// started -> deployed
addEdge(NODE_STARTED,NODE_STOPPING);
addEdge(NODE_STOPPING,NODE_DEPLOYED);
addEdge(STARTED,STOPPING);
addEdge(STOPPING,DEPLOYED);
// deployed -> undeployed
addEdge(NODE_DEPLOYED,NODE_UNDEPLOYING);
addEdge(NODE_UNDEPLOYING,NODE_UNDEPLOYED);
addEdge(DEPLOYED,UNDEPLOYING);
addEdge(UNDEPLOYING,UNDEPLOYED);
}
public void addBinding(AppLifeCycle.Binding binding)
@ -108,6 +110,16 @@ public class AppLifeCycle extends Graph
}
}
public void removeBinding(AppLifeCycle.Binding binding)
{
for (String nodeName : binding.getBindingTargets())
{
List<Binding> bindings = lifecyclebindings.get(nodeName);
if (bindings != null)
bindings.remove(binding);
}
}
/**
* Get all {@link Node} bound objects.
*

View File

@ -22,5 +22,5 @@ import java.util.Map;
*/
public interface ConfigurationManager
{
public Map<?, ?> getProperties();
public Map<String, ?> getProperties();
}

View File

@ -17,12 +17,14 @@ package org.eclipse.jetty.deploy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import org.eclipse.jetty.deploy.bindings.StandardDeployer;
import org.eclipse.jetty.deploy.bindings.StandardStarter;
@ -113,7 +115,7 @@ public class DeploymentManager extends AbstractLifeCycle
private AttributesMap _contextAttributes = new AttributesMap();
private ContextHandlerCollection _contexts;
private boolean _useStandardBindings = true;
private String _defaultLifeCycleGoal = "started";
private String _defaultLifeCycleGoal = AppLifeCycle.STARTED;
/**
* Receive an app for processing.
@ -128,20 +130,49 @@ public class DeploymentManager extends AbstractLifeCycle
entry.setLifeCycleNode(_lifecycle.getNodeByName("undeployed"));
_apps.add(entry);
if (_defaultLifeCycleGoal != null)
if (isRunning() && _defaultLifeCycleGoal != null)
{
// Immediately attempt to go to default lifecycle state
this.requestAppGoal(entry,_defaultLifeCycleGoal);
}
}
public void setAppProviders(Collection<AppProvider> providers)
{
if (isRunning())
throw new IllegalStateException();
_providers.clear();
for (AppProvider provider:providers)
_providers.add(provider);
}
public Collection<AppProvider> getAppProviders()
{
return Collections.unmodifiableList(_providers);
}
public void addAppProvider(AppProvider provider)
{
if (isRunning())
throw new IllegalStateException();
_providers.add(provider);
if (isStarted() || isStarting())
{
startAppProvider(provider);
}
public void setLifeCycleBindings(Collection<AppLifeCycle.Binding> bindings)
{
if (isRunning())
throw new IllegalStateException();
for (AppLifeCycle.Binding b : _lifecycle.getBindings())
_lifecycle.removeBinding(b);
for (AppLifeCycle.Binding b : bindings)
_lifecycle.addBinding(b);
}
public Collection<AppLifeCycle.Binding> getLifeCycleBindings()
{
return Collections.unmodifiableSet(_lifecycle.getBindings());
}
public void addLifeCycleBinding(AppLifeCycle.Binding binding)
@ -261,11 +292,6 @@ public class DeploymentManager extends AbstractLifeCycle
return _apps;
}
public Collection<AppProvider> getAppProviders()
{
return _providers;
}
public Collection<App> getApps()
{
List<App> ret = new ArrayList<App>();
@ -380,8 +406,10 @@ public class DeploymentManager extends AbstractLifeCycle
while (it.hasNext())
{
AppEntry entry = it.next();
if (entry.app.equals(app) && "undeployed".equals(entry.lifecyleNode.getName()))
if (entry.app.equals(app))
{
if (! AppLifeCycle.UNDEPLOYED.equals(entry.lifecyleNode.getName()))
requestAppGoal(entry.app,AppLifeCycle.UNDEPLOYED);
it.remove();
Log.info("Deployable removed: " + entry.app);
}

View File

@ -16,6 +16,7 @@ package org.eclipse.jetty.deploy;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
@ -29,7 +30,7 @@ import org.eclipse.jetty.util.resource.Resource;
public class FileConfigurationManager implements ConfigurationManager
{
private Resource _file;
private Properties _properties = new Properties();
private Map<String,Object> _map = new HashMap<String,Object>();
public FileConfigurationManager()
{
@ -43,12 +44,12 @@ public class FileConfigurationManager implements ConfigurationManager
/**
* @see org.eclipse.jetty.deploy.ConfigurationManager#getProperties()
*/
public Map<?, ?> getProperties()
public Map<String, ?> getProperties()
{
try
{
loadProperties();
return _properties;
return _map;
}
catch (Exception e)
{
@ -58,7 +59,12 @@ public class FileConfigurationManager implements ConfigurationManager
private void loadProperties() throws FileNotFoundException, IOException
{
if (_properties.isEmpty())
_properties.load(_file.getInputStream());
if (_map.isEmpty())
{
Properties properties = new Properties();
properties.load(_file.getInputStream());
for (Map.Entry<Object, Object> entry : properties.entrySet())
_map.put(entry.getKey().toString(),entry.getValue());
}
}
}

View File

@ -38,8 +38,6 @@ public class StandardUndeployer implements AppLifeCycle.Binding
ContextHandlerCollection chcoll = app.getDeploymentManager().getContexts();
recursiveRemoveContext(chcoll,handler);
app.getDeploymentManager().removeApp(app);
}
private void recursiveRemoveContext(HandlerCollection coll, ContextHandler context)

View File

@ -1,21 +0,0 @@
package org.eclipse.jetty.deploy.providers;
import org.eclipse.jetty.deploy.ContextDeployer;
/* ------------------------------------------------------------ */
/** Context directory App Provider.
* <p>This specialisation of {@link MonitoredDirAppProvider} is the
* replacement for {@link ContextDeployer} and it will scan a directory
* only for context.xml files.
* @see ContextDeployer
*/
public class ContextAppProvider extends MonitoredDirAppProvider
{
public ContextAppProvider()
{
super(true,false,false);
setRecursive(false);
}
}

View File

@ -0,0 +1,76 @@
package org.eclipse.jetty.deploy.providers;
import java.io.File;
import java.io.FilenameFilter;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jetty.deploy.App;
import org.eclipse.jetty.deploy.ConfigurationManager;
import org.eclipse.jetty.deploy.ContextDeployer;
import org.eclipse.jetty.deploy.util.FileID;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.xml.XmlConfiguration;
/* ------------------------------------------------------------ */
/** Context directory App Provider.
* <p>This specialisation of {@link MonitoredDirAppProvider} is the
* replacement for {@link ContextDeployer} and it will scan a directory
* only for context.xml files.
* @see ContextDeployer
*/
public class ContextProvider extends AbstractAppProvider
{
private ConfigurationManager _configurationManager;
public ContextProvider()
{
super( new FilenameFilter()
{
public boolean accept(File dir, String name)
{
if (!dir.exists())
return false;
String lowername = name.toLowerCase();
return (lowername.endsWith(".xml") && !new File(dir,name).isDirectory());
}
});
}
/* ------------------------------------------------------------ */
public ConfigurationManager getConfigurationManager()
{
return _configurationManager;
}
/* ------------------------------------------------------------ */
/** Set the configurationManager.
* @param configurationManager the configurationManager to set
*/
public void setConfigurationManager(ConfigurationManager configurationManager)
{
_configurationManager = configurationManager;
}
/* ------------------------------------------------------------ */
public ContextHandler createContextHandler(App app) throws Exception
{
Resource resource = Resource.newResource(app.getArchivePath().toURI());
if (resource.exists() && FileID.isXmlFile(app.getArchivePath()))
{
XmlConfiguration xmlc = new XmlConfiguration(resource.getURL());
Map<String,Object> props = new HashMap<String,Object>();
props.put("Server",getDeploymentManager().getServer());
if (getConfigurationManager() != null)
props.putAll(getConfigurationManager().getProperties());
xmlc.setProperties(props);
return (ContextHandler)xmlc.configure();
}
throw new IllegalStateException("App resouce does not exist "+resource);
}
}

View File

@ -41,6 +41,7 @@ import org.eclipse.jetty.xml.XmlConfiguration;
*
* A Context may either be a WAR, a directory or an XML descriptor.
*
* @deprecated - Use {@link ContextProvider} or {@link WebAppProvider}
*/
public class MonitoredDirAppProvider extends AbstractLifeCycle implements AppProvider
{

View File

@ -1,7 +1,21 @@
package org.eclipse.jetty.deploy.providers;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.jetty.deploy.App;
import org.eclipse.jetty.deploy.ConfigurationManager;
import org.eclipse.jetty.deploy.WebAppDeployer;
import org.eclipse.jetty.deploy.util.FileID;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.xml.XmlConfiguration;
/* ------------------------------------------------------------ */
@ -11,25 +25,190 @@ import org.eclipse.jetty.deploy.WebAppDeployer;
* only for warfiles or directories files.
* @see WebAppDeployer
*/
public class WebAppProvider extends MonitoredDirAppProvider
public class WebAppProvider extends AbstractAppProvider
{
private boolean _extractWars = false;
private boolean _parentLoaderPriority = false;
private String _defaultsDescriptor;
private Filter _filter;
private static class Filter implements FilenameFilter
{
private File _contexts;
public boolean accept(File dir, String name)
{
if (!dir.exists())
return false;
String lowername = name.toLowerCase();
File file = new File(dir,name);
// is it not a directory and not a war ?
if (!file.isDirectory() && !lowername.endsWith(".war"))
return false;
// is it a directory for an existing war file?
if (file.isDirectory() &&
(new File(dir,name+".war").exists() ||
new File(dir,name+".WAR").exists()))
{
return false;
}
// is there a contexts config file
if (_contexts!=null)
{
String context=name;
if (!file.isDirectory())
context=context.substring(0,context.length()-4);
if (new File(_contexts,context+".xml").exists() ||
new File(_contexts,context+".XML").exists() )
{
return false;
}
}
return true;
}
}
/* ------------------------------------------------------------ */
public WebAppProvider()
{
super(false,true,true);
setRecursive(false);
super(new Filter());
_filter=(Filter)_filenameFilter;
setScanInterval(0);
}
/* ------------------------------------------------------------ */
/**
* Configuration Managers are not supported for WebAppProvider, so this
* methods throws an {@link UnsupportedOperationException}.
/** Get the extractWars.
* @return the extractWars
*/
@Override
public void setConfigurationManager(ConfigurationManager configurationManager)
public boolean isExtractWars()
{
throw new UnsupportedOperationException();
return _extractWars;
}
/* ------------------------------------------------------------ */
/** Set the extractWars.
* @param extractWars the extractWars to set
*/
public void setExtractWars(boolean extractWars)
{
_extractWars = extractWars;
}
/* ------------------------------------------------------------ */
/** Get the parentLoaderPriority.
* @return the parentLoaderPriority
*/
public boolean isParentLoaderPriority()
{
return _parentLoaderPriority;
}
/* ------------------------------------------------------------ */
/** Set the parentLoaderPriority.
* @param parentLoaderPriority the parentLoaderPriority to set
*/
public void setParentLoaderPriority(boolean parentLoaderPriority)
{
_parentLoaderPriority = parentLoaderPriority;
}
/* ------------------------------------------------------------ */
/** Get the defaultsDescriptor.
* @return the defaultsDescriptor
*/
public String getDefaultsDescriptor()
{
return _defaultsDescriptor;
}
/* ------------------------------------------------------------ */
/** Set the defaultsDescriptor.
* @param defaultsDescriptor the defaultsDescriptor to set
*/
public void setDefaultsDescriptor(String defaultsDescriptor)
{
_defaultsDescriptor = defaultsDescriptor;
}
/* ------------------------------------------------------------ */
public String getContextXmlDir()
{
return _filter._contexts==null?null:_filter._contexts.toString();
}
/* ------------------------------------------------------------ */
/**
* Set the directory in which to look for context XML files.
* <p>
* If a webapp call "foo/" or "foo.war" is discovered in the monitored
* directory, then the ContextXmlDir is examined to see if a foo.xml
* file exists. If it does, then this deployer will not deploy the webapp
* and the ContextProvider should be used to act on the foo.xml file.
* @see ContextProvider
* @param contextsDir
*/
public void setContextXmlDir(String contextsDir)
{
try
{
_filter._contexts=Resource.newResource(contextsDir).getFile();
}
catch (MalformedURLException e)
{
e.printStackTrace();
}
catch (IOException e)
{
throw new RuntimeException(e);
}
}
/* ------------------------------------------------------------ */
public ContextHandler createContextHandler(final App app) throws Exception
{
Resource resource = Resource.newResource(app.getArchivePath().toURI());
if (!resource.exists())
throw new IllegalStateException("App resouce does not exist "+resource);
String context = app.getArchivePath().getName();
if (app.getArchivePath().isDirectory())
{
// must be a directory
}
else if (FileID.isWebArchiveFile(app.getArchivePath()))
{
// Context Path is the same as the archive.
context = context.substring(0,context.length() - 4);
}
else
throw new IllegalStateException("unable to create ContextHandler for "+app);
// special case of archive (or dir) named "root" is / context
if (context.equalsIgnoreCase("root") || context.equalsIgnoreCase("root/"))
context = URIUtil.SLASH;
// Ensure "/" is Prepended to all context paths.
if (context.charAt(0) != '/')
context = "/" + context;
// Ensure "/" is Not Trailing in context paths.
if (context.endsWith("/") && context.length() > 0)
context = context.substring(0,context.length() - 1);
WebAppContext wah = new WebAppContext();
wah.setContextPath(context);
wah.setWar(app.getArchivePath().getAbsolutePath());
if (_defaultsDescriptor != null)
wah.setDefaultsDescriptor(_defaultsDescriptor);
wah.setExtractWAR(_extractWars);
wah.setParentLoaderPriority(_parentLoaderPriority);
return wah;
}
}

View File

@ -11,14 +11,12 @@
</Set>
<!-- Providers of Apps -->
<Call name="addAppProvider">
<Arg>
<New class="org.eclipse.jetty.deploy.providers.MonitoredDirAppProvider">
<Set name="monitoredDir">
<Property name="jetty.home" />/contexts
</Set>
<Set name="appProviders">
<Array type="org.eclipse.jetty.deploy.AppProvider">
<Item>
<New class="org.eclipse.jetty.deploy.providers.ContextProvider">
<Set name="monitoredDir"><Property name="jetty.home" />/contexts</Set>
<Set name="scanInterval">1</Set>
<Set name="recursive">true</Set>
<Set name="configurationManager">
<New class="org.eclipse.jetty.deploy.FileConfigurationManager">
<Set name="file">
@ -27,8 +25,16 @@
</New>
</Set>
</New>
</Arg>
</Call>
</Item>
<Item>
<New class="org.eclipse.jetty.deploy.providers.WebAppProvider">
<Set name="monitoredDir"><Property name="jetty.home" />/webapps</Set>
<Set name="scanInterval">1</Set>
<Set name="contextXmlDir"><Property name="jetty.home" />/contexts</Set>
</New>
</Item>
</Array>
</Set>
</New>
</Arg>
</Call>

View File

@ -129,6 +129,7 @@
<Set name="monitoredDir"><Property name="jetty.home" default="." />/webapps</Set>
<Set name="defaultsDescriptor"><SystemProperty name="jetty.home" default="."/>/etc/webdefault.xml</Set>
<Set name="scanInterval">5</Set>
<Set name="contextXmlDir"><Property name="jetty.home" default="." />/contexts</Set>
</New>
</Arg>
</Call>

View File

@ -248,7 +248,6 @@ public class Server extends HandlerWrapper implements Attributes
if (Log.isDebugEnabled())
Log.debug(dump());
System.err.println(dump());
mex.ifExceptionThrow();
}

View File

@ -398,8 +398,21 @@ public class WebInfConfiguration implements Configuration
!web_app.isDirectory())
)
{
// Look for sibling directory.
File extractedWebAppDir = null;
if (war!=null)
{
// look for a sibling like "foo/" to a "foo.war"
File warfile=Resource.newResource(war).getFile();
File sibling = new File(warfile.getParent(),warfile.getName().substring(0,warfile.getName().length()-4));
if (sibling.exists() && sibling.isDirectory() && sibling.canWrite())
extractedWebAppDir=sibling;
}
if (extractedWebAppDir==null)
// Then extract it if necessary to the temporary location
File extractedWebAppDir= new File(context.getTempDirectory(), "webapp");
extractedWebAppDir= new File(context.getTempDirectory(), "webapp");
if (web_app.getFile()!=null && web_app.getFile().isDirectory())
{
@ -440,7 +453,6 @@ public class WebInfConfiguration implements Configuration
throw new java.io.FileNotFoundException(war);
}
context.setBaseResource(web_app);
if (Log.isDebugEnabled())

View File

@ -28,10 +28,16 @@ import java.net.UnknownHostException;
import java.security.AccessControlException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.eclipse.jetty.util.LazyList;
import org.eclipse.jetty.util.Loader;
@ -364,8 +370,11 @@ public class XmlConfiguration
Method set = null;
for (int s = 0; sets != null && s < sets.length; s++)
{
if (name.equals(sets[s].getName()) && sets[s].getParameterTypes().length == 1)
Class<?>[] paramTypes= sets[s].getParameterTypes();
if (name.equals(sets[s].getName()) && paramTypes.length == 1)
{
// lets try it
try
{
@ -381,6 +390,28 @@ public class XmlConfiguration
{
Log.ignore(e);
}
// Can we convert to a collection
if (paramTypes[0].isAssignableFrom(Collection.class) && value.getClass().isArray())
{
try
{
if (paramTypes[0].isAssignableFrom(Set.class))
sets[s].invoke(obj, new Object[]{new HashSet<Object>(Arrays.asList((Object[])value))});
else
sets[s].invoke(obj, new Object[]{Arrays.asList((Object[])value)});
return;
}
catch (IllegalArgumentException e)
{
Log.ignore(e);
}
catch (IllegalAccessException e)
{
Log.ignore(e);
}
}
}
}