Merge remote-tracking branch 'origin/master' into servlet-3.1-api

Conflicts:
	jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java
This commit is contained in:
Greg Wilkins 2013-05-28 22:51:31 +10:00
commit 942f8a5c40
50 changed files with 1021 additions and 716 deletions

View File

@ -1,3 +1,5 @@
jetty-9.0.4-SNAPSHOT
jetty-9.0.3.v20130506 06 May 2013
+ 404010 fix cast exception in mongodb session manager
+ 404911 WebSocketCloseTest fails spuriously
@ -164,6 +166,34 @@ jetty-9.0.0.v20130308 - 08 March 2013
+ 402757 WebSocket client module can't be used with WebSocket server module in
the same WAR
jetty-8.1.11.v20130520 - 20 May 2013
+ 402844 STOP.PORT & STOP.KEY behaviour has changed
+ 403281 jetty.sh waits for started or failure before returning
+ 403513 jetty:run goal cannot be executed twice during the maven build
+ 403570 Asynchronous Request Logging
+ 404010 fix cast exception in mongodb session manager
+ 404128 Add Vary headers rather than set them
+ 404283 org.eclipse.jetty.util.Scanner.scanFile() dies with an NPE if
listFiles() returns null
+ 404325 data constraint redirection does send default port
+ 404517 Close connection if request received after half close
+ 404789 Support IPv6 addresses in DoSFilter white list.
+ 404958 Fixed Resource.newSystemResource striped / handling
+ 405281 allow filemappedbuffers to not be used
+ 405537 NPE in rendering JSP using SPDY and wrapped ServletRequest
+ 406437 Digest Auth supports out of order nc
+ 406618 Jetty startup in OSGi Equinox fails when using option
jetty.home.bundle=org.eclipse.jetty.osgi.boot
+ 406923 CR line termination
+ 407136 @PreDestroy called after Servlet.destroy()
+ 407173 java.lang.IllegalStateException: null when using JDBCSessionManager
+ 407931 Add toggle for failing on servlet availability
+ 407976 JDBCSessionIdManager potentially leaves server in bad state after
startup
+ 408077 HashSessionManager leaves file handles open after being stopped
+ 408446 Multipart parsing issue with boundry and charset in ContentType
header
jetty-8.1.10.v20130312 - 12 March 2013
+ 376273 Early EOF because of SSL Protocol Error on
https://api-3t.paypal.com/nvp.
@ -200,6 +230,31 @@ jetty-8.1.10.v20130312 - 12 March 2013
+ 402833 Test harness for global error page and hide exception message from
reason string
jetty-7.6.11.v20130520 - 20 May 2013
+ 402844 STOP.PORT & STOP.KEY behaviour has changed
+ 403281 jetty.sh waits for started or failure before returning
+ 403513 jetty:run goal cannot be executed twice during the maven build
+ 403570 Asynchronous Request Logging
+ 404010 fix cast exception in mongodb session manager
+ 404128 Add Vary headers rather than set them
+ 404283 org.eclipse.jetty.util.Scanner.scanFile() dies with an NPE if
listFiles() returns null
+ 404325 data constraint redirection does send default port
+ 404517 Close connection if request received after half close
+ 404789 Support IPv6 addresses in DoSFilter white list.
+ 404958 Fixed Resource.newSystemResource striped / handling
+ 405281 allow filemappedbuffers to not be used
+ 405537 NPE in rendering JSP using SPDY and wrapped ServletRequest
+ 406437 Digest Auth supports out of order nc
+ 406923 CR line termination
+ 407136 @PreDestroy called after Servlet.destroy()
+ 407173 java.lang.IllegalStateException: null when using JDBCSessionManager
+ 407976 JDBCSessionIdManager potentially leaves server in bad state after
startup
+ 408077 HashSessionManager leaves file handles open after being stopped
+ 408446 Multipart parsing issue with boundry and charset in ContentType
header
jetty-7.6.10.v20130312 - 12 March 2013
+ 376273 Early EOF because of SSL Protocol Error on
https://api-3t.paypal.com/nvp.

View File

@ -21,11 +21,20 @@ package org.eclipse.jetty.ant;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Array;
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.CodeSource;
import java.security.PermissionCollection;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.jar.Manifest;
import javax.servlet.Servlet;
@ -44,6 +53,8 @@ import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.servlet.Holder;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.Configuration;
import org.eclipse.jetty.webapp.FragmentConfiguration;
@ -65,6 +76,8 @@ import org.eclipse.jetty.xml.XmlConfiguration;
*/
public class AntWebAppContext extends WebAppContext
{
private static final Logger LOG = Log.getLogger(WebAppContext.class);
public final AntWebInfConfiguration antWebInfConfiguration = new AntWebInfConfiguration();
public final WebXmlConfiguration webXmlConfiguration = new WebXmlConfiguration();
public final MetaInfConfiguration metaInfConfiguration = new MetaInfConfiguration();
@ -142,6 +155,184 @@ public class AntWebAppContext extends WebAppContext
}
/**
* AntURLClassLoader
*
* Adapt the AntClassLoader which is not a URLClassLoader - this is needed for
* jsp to be able to search the classpath.
*/
public static class AntURLClassLoader extends URLClassLoader
{
private AntClassLoader antLoader;
public AntURLClassLoader(AntClassLoader antLoader)
{
super(new URL[] {}, antLoader);
this.antLoader = antLoader;
}
@Override
public InputStream getResourceAsStream(String name)
{
return super.getResourceAsStream(name);
}
@Override
public void close() throws IOException
{
super.close();
}
@Override
protected void addURL(URL url)
{
super.addURL(url);
}
@Override
public URL[] getURLs()
{
Set<URL> urls = new HashSet<URL>();
//convert urls from antLoader
String[] paths = antLoader.getClasspath().split(new String(new char[]{File.pathSeparatorChar}));
if (paths != null)
{
for (String p:paths)
{
File f = new File(p);
try
{
urls.add(f.toURI().toURL());
}
catch (Exception e)
{
LOG.ignore(e);
}
}
}
//add in any that may have been added to us as a URL directly
URL[] ourURLS = super.getURLs();
if (ourURLS != null)
{
for (URL u:ourURLS)
urls.add(u);
}
return urls.toArray(new URL[urls.size()]);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException
{
return super.findClass(name);
}
@Override
protected Package definePackage(String name, Manifest man, URL url) throws IllegalArgumentException
{
return super.definePackage(name, man, url);
}
@Override
public URL findResource(String name)
{
return super.findResource(name);
}
@Override
public Enumeration<URL> findResources(String name) throws IOException
{
return super.findResources(name);
}
@Override
protected PermissionCollection getPermissions(CodeSource codesource)
{
return super.getPermissions(codesource);
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException
{
return super.loadClass(name);
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
{
return super.loadClass(name, resolve);
}
@Override
protected Object getClassLoadingLock(String className)
{
return super.getClassLoadingLock(className);
}
@Override
public URL getResource(String name)
{
return super.getResource(name);
}
@Override
public Enumeration<URL> getResources(String name) throws IOException
{
return super.getResources(name);
}
@Override
protected Package definePackage(String name, String specTitle, String specVersion, String specVendor, String implTitle, String implVersion,
String implVendor, URL sealBase) throws IllegalArgumentException
{
return super.definePackage(name, specTitle, specVersion, specVendor, implTitle, implVersion, implVendor, sealBase);
}
@Override
protected Package getPackage(String name)
{
return super.getPackage(name);
}
@Override
protected Package[] getPackages()
{
return super.getPackages();
}
@Override
protected String findLibrary(String libname)
{
return super.findLibrary(libname);
}
@Override
public void setDefaultAssertionStatus(boolean enabled)
{
super.setDefaultAssertionStatus(enabled);
}
@Override
public void setPackageAssertionStatus(String packageName, boolean enabled)
{
super.setPackageAssertionStatus(packageName, enabled);
}
@Override
public void setClassAssertionStatus(String className, boolean enabled)
{
super.setClassAssertionStatus(className, enabled);
}
@Override
public void clearAssertionStatus()
{
super.clearAssertionStatus();
}
}
/**
* AntServletHolder
@ -180,31 +371,6 @@ public class AntWebAppContext extends WebAppContext
super(name, servlet);
}
@Override
protected void initJspServlet() throws Exception
{
//super.initJspServlet();
ContextHandler ch = ContextHandler.getContextHandler(getServletHandler().getServletContext());
/* Set the webapp's classpath for Jasper */
ch.setAttribute("org.apache.catalina.jsp_classpath", ch.getClassPath());
/* Set the system classpath for Jasper */
String sysClassPath = getSystemClassPath(ch.getClassLoader().getParent());
setInitParameter("com.sun.appserv.jsp.classpath", sysClassPath);
/* Set up other classpath attribute */
if ("?".equals(getInitParameter("classpath")))
{
String classpath = ch.getClassPath();
if (classpath != null)
setInitParameter("classpath", classpath);
}
}
protected String getSystemClassPath (ClassLoader loader) throws Exception
{
StringBuilder classpath=new StringBuilder();
@ -465,7 +631,7 @@ public class AntWebAppContext extends WebAppContext
/**
* @see WebApplicationProxy#start()
*
*/
public void doStart()
{
@ -474,7 +640,12 @@ public class AntWebAppContext extends WebAppContext
TaskLog.logWithTimestamp("Starting web application "+this.getDescriptor());
if (jettyEnvXml != null && jettyEnvXml.exists())
envConfiguration.setJettyEnvXml(Resource.toURL(jettyEnvXml));
setClassLoader(new WebAppClassLoader(this.getClass().getClassLoader(), this));
ClassLoader parentLoader = this.getClass().getClassLoader();
if (parentLoader instanceof AntClassLoader)
parentLoader = new AntURLClassLoader((AntClassLoader)parentLoader);
setClassLoader(new WebAppClassLoader(parentLoader, this));
if (attributes != null && attributes.getAttributes() != null)
{
for (Attribute a:attributes.getAttributes())

View File

@ -278,6 +278,7 @@ public class ServerProxyImpl implements ServerProxy
}
catch (Exception e)
{
e.printStackTrace();
new RuntimeException(e);
}
}
@ -351,11 +352,14 @@ public class ServerProxyImpl implements ServerProxy
return;
configured = true;
ShutdownMonitor monitor = ShutdownMonitor.getInstance();
monitor.setPort(stopPort);
monitor.setKey(stopKey);
monitor.setExitVm(false);
if(stopPort>0 && stopKey!=null)
{
ShutdownMonitor monitor = ShutdownMonitor.getInstance();
monitor.setPort(stopPort);
monitor.setKey(stopKey);
monitor.setExitVm(false);
}
if (tempDirectory != null && !tempDirectory.exists())
tempDirectory.mkdirs();

View File

@ -7,11 +7,10 @@
<!-- To use: -->
<!-- * mkdir test-jetty-ant -->
<!-- * cp this file to test-jetty-ant -->
<!-- * cd test-jetty-ant; mkdir jetty-lib; mkdir war; mkdir jetty-temp -->
<!-- * cd test-jetty-ant; mkdir jetty-lib; mkdir jetty-temp -->
<!-- * copy all jars from $JETTY_HOME/lib and all subdirs flatly into ./jetty-lib -->
<!-- * unjar the test.war from $JETTY_HOME/webapps dir into ./war -->
<!-- * cp $JETTY_HOME/etc/webdefaults.xml to . -->
<!-- * cp $JETTY_HOME/etc/realm.properties to . -->
<!-- * copy the jetty-ant jar into ./jetty-lib -->
<!-- * copy the test.war from $JETTY_HOME/webapps.demo dir -->
<!-- -->
<!-- To run: -->
<!-- ant jetty.run -->
@ -30,12 +29,12 @@
<loginServices>
<hashLoginService name="Test Realm" config="realm.properties"/>
</loginServices>
<webApp name="test"
warfile="war"
webDefaultXmlFile="webdefault.xml"
<webApp
war="test.war"
contextpath="/test" >
<attributes>
<attribute name="org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern" value=".*/.*jsp-api-[^/]*\.jar$|.*/.*jsp-[^/]*\.jar$|.*/.*taglibs[^/]*\.jar$"/>
<attribute name="org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern" value=".*/servlet-api-[^/]*\.jar$"/>
</attributes>
</webApp>
</jetty.run>

View File

@ -30,8 +30,7 @@ import org.junit.Test;
public class JettyAntTaskTest
{
@Ignore
//@Test
@Test
public void testConnectorTask() throws Exception
{
AntBuild build = new AntBuild(MavenTestingUtils.getTestResourceFile("connector-test.xml").getAbsolutePath());
@ -51,7 +50,6 @@ public class JettyAntTaskTest
@Test
@Ignore("need to update connector")
public void testWebApp () throws Exception
{
AntBuild build = new AntBuild(MavenTestingUtils.getTestResourceFile("webapp-test.xml").getAbsolutePath());

View File

@ -25,7 +25,7 @@ import java.util.Enumeration;
import java.util.LinkedHashSet;
import org.eclipse.jetty.osgi.boot.OSGiWebappConstants;
import org.eclipse.jetty.osgi.boot.internal.webapp.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.osgi.boot.utils.internal.DefaultFileLocatorHelper;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -115,24 +115,24 @@ public class TagLibOSGiConfiguration extends TagLibConfiguration
{
atLeastOneTldFound = true;
URL oriUrl = en.nextElement();
URL url = BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(oriUrl);
Resource tldResource;
try
{
URL url = BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(oriUrl);
Resource tldResource;
tldResource = Resource.newResource(url);
tlds.add(tldResource);
}
catch (IOException e)
catch (Exception e)
{
throw new IllegalArgumentException("Unable to locate the " + "tld resource in '"
+ url.toString()
+ "' in the bundle '"
+ bs[0].getSymbolicName()
+ "' while registering the "
+ OSGiWebappConstants.REQUIRE_TLD_BUNDLE
+ " of the manifest of "
+ bundle.getSymbolicName(), e);
+ oriUrl.toString()
+ "' in the bundle '"
+ bs[0].getSymbolicName()
+ "' while registering the "
+ OSGiWebappConstants.REQUIRE_TLD_BUNDLE
+ " of the manifest of "
+ bundle.getSymbolicName(), e);
}
tlds.add(tldResource);
}
if (!atLeastOneTldFound)
{

View File

@ -12,6 +12,15 @@
<Arg>
<New class="org.eclipse.jetty.server.ServerConnector">
<Arg><Ref refid="Server" /></Arg>
<Arg name="factories">
<Array type="org.eclipse.jetty.server.ConnectionFactory">
<Item>
<New class="org.eclipse.jetty.server.HttpConnectionFactory">
<Arg name="config"><Ref refid="httpConfig" /></Arg>
</New>
</Item>
</Array>
</Arg>
<Set name="host"><Property name="jetty.host" /></Set>
<Set name="port"><Property name="jetty.port" default="8080"/></Set>
<Set name="idleTimeout">300000</Set>

View File

@ -14,7 +14,7 @@
<!-- =========================================================== -->
<!-- Server Thread Pool -->
<!-- =========================================================== -->
<Arg name="threadPool">
<Arg name="threadpool">
<!-- Default queued blocking threadpool -->
<New class="org.eclipse.jetty.util.thread.QueuedThreadPool">
<Set name="minThreads">10</Set>
@ -44,6 +44,17 @@
</New>
</Set>
<New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
<Set name="secureScheme">https</Set>
<Set name="securePort"><Property name="jetty.secure.port" default="8443" /></Set>
<Set name="outputBufferSize">32768</Set>
<Set name="requestHeaderSize">8192</Set>
<Set name="responseHeaderSize">8192</Set>
<Set name="sendServerVersion">true</Set>
<Set name="sendDateHeader">false</Set>
<Set name="headerCacheSize">512</Set>
</New>
<!-- =========================================================== -->
<!-- extra options -->

View File

@ -27,7 +27,7 @@ import org.eclipse.jetty.deploy.App;
import org.eclipse.jetty.deploy.AppProvider;
import org.eclipse.jetty.deploy.DeploymentManager;
import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
import org.eclipse.jetty.osgi.boot.internal.webapp.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.osgi.boot.utils.OSGiClassLoader;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
@ -214,7 +214,7 @@ public abstract class AbstractContextProvider extends AbstractLifeCycle implemen
//put the server instance in
properties.put("Server", getServerInstanceWrapper().getServer());
//put in the location of the bundle root
properties.put("bundle.root", rootResource.toString());
properties.put(OSGiWebappConstants.JETTY_BUNDLE_ROOT, rootResource.toString());
// insert the bundle's location as a property.
xmlConfiguration.getProperties().putAll(properties);

View File

@ -28,12 +28,14 @@ import org.eclipse.jetty.deploy.App;
import org.eclipse.jetty.deploy.AppProvider;
import org.eclipse.jetty.deploy.DeploymentManager;
import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
import org.eclipse.jetty.osgi.boot.internal.webapp.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.osgi.boot.internal.webapp.OSGiWebappClassLoader;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.JarResource;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.xml.XmlConfiguration;
import org.osgi.framework.Bundle;
@ -195,7 +197,15 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement
? BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(_bundle)
: new File(overrideBundleInstallLocation));
URL url = null;
Resource rootResource = Resource.newResource(BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(bundleInstallLocation.toURI().toURL()));
//try and make sure the rootResource is useable - if its a jar then make it a jar file url
if (rootResource.exists()&& !rootResource.isDirectory() && !rootResource.toString().startsWith("jar:"))
{
Resource jarResource = JarResource.newJarResource(rootResource);
if (jarResource.exists() && jarResource.isDirectory())
rootResource = jarResource;
}
//if the path wasn't set or it was ., then it is the root of the bundle's installed location
if (_webAppPath == null || _webAppPath.length() == 0 || ".".equals(_webAppPath))
{
@ -227,6 +237,7 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement
+ (bundleInstallLocation != null ? bundleInstallLocation.getAbsolutePath() : "unlocated bundle '" + _bundle.getSymbolicName()+ "'"));
}
//Sets the location of the war file
// converts bundleentry: protocol if necessary
_webApp.setWar(BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(url).toString());
@ -283,7 +294,7 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement
// apply any META-INF/context.xml file that is found to configure
// the webapp first
applyMetaInfContextXml();
applyMetaInfContextXml(rootResource);
// pass the value of the require tld bundle so that the TagLibOSGiConfiguration
// can pick it up.
@ -341,7 +352,7 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement
}
protected void applyMetaInfContextXml()
protected void applyMetaInfContextXml(Resource rootResource)
throws Exception
{
if (_bundle == null) return;
@ -365,6 +376,7 @@ public abstract class AbstractWebAppProvider extends AbstractLifeCycle implement
XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXmlUrl);
HashMap properties = new HashMap();
properties.put("Server", getDeploymentManager().getServer());
properties.put(OSGiWebappConstants.JETTY_BUNDLE_ROOT, rootResource.toString());
xmlConfiguration.getProperties().putAll(properties);
xmlConfiguration.configure(_webApp);
}

View File

@ -23,7 +23,7 @@ import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import org.eclipse.jetty.osgi.boot.internal.webapp.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;

View File

@ -27,7 +27,7 @@ import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.regex.Pattern;
import org.eclipse.jetty.osgi.boot.internal.webapp.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;

View File

@ -79,6 +79,10 @@ public class OSGiWebappConstants
public static final String JETTY_WAR_PATCH_FRAGMENT_FOLDER_PATH = "Jetty-WarPatchFragmentFolderPath";
/** installation path of webapp bundle
*
*/
public static final String JETTY_BUNDLE_ROOT = "bundle.root";
/**
* web app context path
* @deprecated see RFC66_WEB_CONTEXTPATH

View File

@ -20,18 +20,25 @@ package org.eclipse.jetty.osgi.boot.internal.serverfactory;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.List;
import java.util.StringTokenizer;
import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator;
import org.eclipse.jetty.osgi.boot.OSGiServerConstants;
import org.eclipse.jetty.osgi.boot.internal.webapp.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.osgi.boot.utils.OSGiClassLoader;
import org.eclipse.jetty.osgi.boot.utils.Util;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.JarResource;
import org.eclipse.jetty.util.resource.Resource;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
@ -63,7 +70,7 @@ public class DefaultJettyAtJettyHomeHelper
/**
* Default location within bundle of a jetty home dir.
*/
public static final String DEFAULT_JETTYHOME = "/jettyhome/";
public static final String DEFAULT_JETTYHOME = "/jettyhome";
@ -80,9 +87,7 @@ public class DefaultJettyAtJettyHomeHelper
* In both cases reads the system property 'jetty.etc.config.urls' to locate
* the configuration files for the deployed jetty. It is a comma separated
* list of URLs or relative paths inside the bundle or folder to the config
* files. If undefined it defaults to 'etc/jetty.xml'. In the case of the jetty.home.bundle,
* if no etc/jetty.xml file is found in the bundle, it will look for
* /jettyhome/etc/jetty-osgi-default.xml
* files.
* </p>
* <p>
* In both cases the system properties jetty.host, jetty.port and
@ -94,30 +99,33 @@ public class DefaultJettyAtJettyHomeHelper
{
String jettyHomeSysProp = System.getProperty(OSGiServerConstants.JETTY_HOME);
String jettyHomeBundleSysProp = System.getProperty(OSGiServerConstants.JETTY_HOME_BUNDLE);
File jettyHome = null;
File jettyHomeDir = null;
Bundle jettyHomeBundle = null;
Dictionary<String,String> properties = new Hashtable<String,String>();
if (jettyHomeSysProp != null)
{
jettyHomeSysProp = resolvePropertyValue(jettyHomeSysProp);
jettyHomeSysProp = Util.resolvePropertyValue(jettyHomeSysProp);
// bug 329621
if (jettyHomeSysProp.startsWith("\"") && jettyHomeSysProp.endsWith("\"") || (jettyHomeSysProp.startsWith("'") && jettyHomeSysProp.endsWith("'")))
{
jettyHomeSysProp = jettyHomeSysProp.substring(1, jettyHomeSysProp.length() - 1);
}
if (jettyHomeBundleSysProp != null)
{
LOG.warn("Both jetty.home and jetty.home.bundle property defined: jetty.home.bundle ignored.");
}
jettyHome = new File(jettyHomeSysProp);
if (!jettyHome.exists() || !jettyHome.isDirectory())
jettyHomeDir = new File(jettyHomeSysProp);
if (!jettyHomeDir.exists() || !jettyHomeDir.isDirectory())
{
LOG.warn("Unable to locate the jetty.home folder " + jettyHomeSysProp);
return null;
}
//set jetty.home
Util.setProperty(properties, OSGiServerConstants.JETTY_HOME, jettyHomeDir.getAbsolutePath());
}
else if (jettyHomeBundleSysProp != null)
{
jettyHomeBundleSysProp = resolvePropertyValue(jettyHomeBundleSysProp);
jettyHomeBundleSysProp = Util.resolvePropertyValue(jettyHomeBundleSysProp);
for (Bundle b : bundleContext.getBundles())
{
if (b.getSymbolicName().equals(jettyHomeBundleSysProp))
@ -131,38 +139,52 @@ public class DefaultJettyAtJettyHomeHelper
LOG.warn("Unable to find the jetty.home.bundle named " + jettyHomeSysProp);
return null;
}
}
if (jettyHome == null && jettyHomeBundle == null)
if (jettyHomeDir == null && jettyHomeBundle == null)
{
LOG.warn("No default jetty created.");
return null;
}
Server server = new Server();
Dictionary<String,String> properties = new Hashtable<String,String>();
properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME);
String configURLs = jettyHome != null ? getJettyConfigurationURLs(jettyHome) : getJettyConfigurationURLs(jettyHomeBundle);
properties.put(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS, configURLs);
LOG.info("Configuring the default jetty server with " + configURLs);
// these properties usually are the ones passed to this type of
// configuration.
setProperty(properties, OSGiServerConstants.JETTY_HOME, System.getProperty(OSGiServerConstants.JETTY_HOME));
setProperty(properties, OSGiServerConstants.JETTY_HOST, System.getProperty(OSGiServerConstants.JETTY_HOST));
setProperty(properties, OSGiServerConstants.JETTY_PORT, System.getProperty(OSGiServerConstants.JETTY_PORT));
setProperty(properties, OSGiServerConstants.JETTY_PORT_SSL, System.getProperty(OSGiServerConstants.JETTY_PORT_SSL));
//Register the default Server instance as an OSGi service.
//The JettyServerServiceTracker will notice it and configure it.
bundleContext.registerService(Server.class.getName(), server, properties);
return server;
//configure the server here rather than letting the JettyServerServiceTracker do it, because we want to be able to
//configure the ThreadPool, which can only be done via the constructor, ie from within the xml configuration processing
List<URL> configURLs = jettyHomeDir != null ? getJettyConfigurationURLs(jettyHomeDir) : getJettyConfigurationURLs(jettyHomeBundle, properties);
LOG.info("Configuring the default jetty server with {}",configURLs);
LOG.info("JETTY.HOME="+properties.get(OSGiServerConstants.JETTY_HOME));
ClassLoader contextCl = Thread.currentThread().getContextClassLoader();
try
{
Thread.currentThread().setContextClassLoader(JettyBootstrapActivator.class.getClassLoader());
// these properties usually are the ones passed to this type of
// configuration.
properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME);
Util.setProperty(properties, OSGiServerConstants.JETTY_HOST, System.getProperty(OSGiServerConstants.JETTY_HOST));
Util.setProperty(properties, OSGiServerConstants.JETTY_PORT, System.getProperty(OSGiServerConstants.JETTY_PORT));
Util.setProperty(properties, OSGiServerConstants.JETTY_PORT_SSL, System.getProperty(OSGiServerConstants.JETTY_PORT_SSL));
Server server = ServerInstanceWrapper.configure(null, configURLs, properties);
//ensure jetty.home is set
server.setAttribute(OSGiServerConstants.JETTY_HOME, properties.get(OSGiServerConstants.JETTY_HOME));
//Register the default Server instance as an OSGi service.
//The JettyServerServiceTracker will notice it and set it up to deploy bundles as wars etc
bundleContext.registerService(Server.class.getName(), server, properties);
LOG.info("Default jetty server configured");
return server;
}
finally
{
Thread.currentThread().setContextClassLoader(contextCl);
}
}
/* ------------------------------------------------------------ */
/**
@ -173,33 +195,26 @@ public class DefaultJettyAtJettyHomeHelper
*
* @param jettyhome
* @return
* @throws MalformedURLException
*/
private static String getJettyConfigurationURLs(File jettyhome)
private static List<URL> getJettyConfigurationURLs(File jettyhome)
throws MalformedURLException
{
List<URL> configURLs = new ArrayList<URL>();
String jettyetc = System.getProperty(JETTY_ETC_FILES, DEFAULT_JETTY_ETC_FILES);
StringTokenizer tokenizer = new StringTokenizer(jettyetc, ";,", false);
StringBuilder res = new StringBuilder();
while (tokenizer.hasMoreTokens())
{
String next = tokenizer.nextToken().trim();
if (!next.startsWith("/") && next.indexOf(':') == -1)
{
try
{
next = new File(jettyhome, next).toURI().toURL().toString();
}
catch (MalformedURLException e)
{
LOG.warn(e);
continue;
}
}
appendToCommaSeparatedList(res, next);
//etc files can either be relative to jetty.home or absolute disk locations
if (!next.startsWith("/") && (next.indexOf(':') == -1))
configURLs.add(new File(jettyhome, next).toURI().toURL());
else
configURLs.add(new URL(next));
}
return res.toString();
return configURLs;
}
/* ------------------------------------------------------------ */
/**
* Minimum setup for the location of the configuration files given a
@ -210,118 +225,90 @@ public class DefaultJettyAtJettyHomeHelper
* @param jettyhome
* @return
*/
private static String getJettyConfigurationURLs(Bundle configurationBundle)
private static List<URL> getJettyConfigurationURLs(Bundle configurationBundle, Dictionary properties)
throws Exception
{
String files = System.getProperty(JETTY_ETC_FILES, DEFAULT_JETTY_ETC_FILES);
List<URL> configURLs = new ArrayList<URL>();
String files = System.getProperty(JETTY_ETC_FILES, DEFAULT_JETTY_ETC_FILES);
StringTokenizer tokenizer = new StringTokenizer(files, ";,", false);
StringBuilder res = new StringBuilder();
while (tokenizer.hasMoreTokens())
{
String etcFile = tokenizer.nextToken().trim();
//file path is absolute
if (etcFile.startsWith("/") || etcFile.indexOf(":") != -1)
configURLs.add(new URL(etcFile));
else //relative file path
{
//file path is absolute
appendToCommaSeparatedList(res, etcFile);
}
else
{
//relative file path
Enumeration<URL> enUrls = BundleFileLocatorHelperFactory.getFactory().getHelper().findEntries(configurationBundle, etcFile);
String home = null;
// default for org.eclipse.osgi.boot where we look inside
// jettyhome for the default embedded configuration.
// default inside jettyhome. this way fragments to the bundle
// can define their own configuration.
// jettyhome/ for the default embedded configuration.
if ((enUrls == null || !enUrls.hasMoreElements()))
{
home = DEFAULT_JETTYHOME;
String tmp = DEFAULT_JETTYHOME+(DEFAULT_JETTYHOME.endsWith("/")?"":"/")+etcFile;
enUrls = BundleFileLocatorHelperFactory.getFactory().getHelper().findEntries(configurationBundle, tmp);
LOG.info("Configuring jetty from bundle: "
+ configurationBundle.getSymbolicName()
+ " with "+tmp);
LOG.info("Configuring jetty from bundle: {} with {}", configurationBundle.getSymbolicName(),tmp);
}
//lazily ensure jetty.home value is set based on location of etc files
if (properties.get(OSGiServerConstants.JETTY_HOME) == null)
{
Resource res = findDir(configurationBundle, home);
if (res != null)
properties.put(OSGiServerConstants.JETTY_HOME, res.toString());
}
if (enUrls == null || !enUrls.hasMoreElements())
{
throw new IllegalStateException ("Unable to locate a jetty configuration file for " + etcFile);
}
if (enUrls != null)
{
while (enUrls.hasMoreElements())
{
URL url = BundleFileLocatorHelperFactory.getFactory().getHelper().getFileURL(enUrls.nextElement());
appendToCommaSeparatedList(res, url.toString());
}
}
URL url = BundleFileLocatorHelperFactory.getFactory().getHelper().getFileURL(enUrls.nextElement());
configURLs.add(url);
}
}
return res.toString();
return configURLs;
}
/* ------------------------------------------------------------ */
private static void appendToCommaSeparatedList(StringBuilder buffer, String value)
{
if (buffer.length() != 0)
{
buffer.append(",");
}
buffer.append(value);
}
/* ------------------------------------------------------------ */
private static void setProperty(Dictionary<String,String> properties, String key, String value)
{
if (value != null)
{
properties.put(key, value);
}
}
/* ------------------------------------------------------------ */
/**
* recursively substitute the ${sysprop} by their actual system property.
* ${sysprop,defaultvalue} will use 'defaultvalue' as the value if no
* sysprop is defined. Not the most efficient code but we are shooting for
* simplicity and speed of development here.
*
* @param value
* Get a resource representing a directory inside a bundle. If the dir is null,
* return a resource representing the installation location of the bundle.
* @param bundle
* @param dir
* @return
*/
public static String resolvePropertyValue(String value)
public static Resource findDir (Bundle bundle, String dir)
{
int ind = value.indexOf("${");
if (ind == -1) { return value; }
int ind2 = value.indexOf('}', ind);
if (ind2 == -1) { return value; }
String sysprop = value.substring(ind + 2, ind2);
String defaultValue = null;
int comma = sysprop.indexOf(',');
if (comma != -1 && comma + 1 != sysprop.length())
{
defaultValue = sysprop.substring(comma + 1);
defaultValue = resolvePropertyValue(defaultValue);
sysprop = sysprop.substring(0, comma);
}
else
{
defaultValue = "${" + sysprop + "}";
}
if (bundle == null)
return null;
String v = System.getProperty(sysprop);
String reminder = value.length() > ind2 + 1 ? value.substring(ind2 + 1) : "";
reminder = resolvePropertyValue(reminder);
if (v != null)
try
{
return value.substring(0, ind) + v + reminder;
File f = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(bundle);
URL u = f.toURI().toURL();
u = BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(u);
Resource res = Resource.newResource(u);
String s = res.toString();
//check if it is an unarchived bundle
if (s.endsWith(".jar") && s.startsWith("file:"))
res = JarResource.newJarResource(res);
//if looking for a directory
if (dir != null)
res = res.addPath(dir);
return res;
}
else
catch (Exception e)
{
return value.substring(0, ind) + defaultValue + reminder;
LOG.warn("Bad bundle location" , e);
return null;
}
}
}

View File

@ -1,34 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.osgi.boot.internal.serverfactory;
/**
* Keeps track of the running jetty servers. They are named.
*/
public interface IManagedJettyServerRegistry
{
/**
* @param managedServerName The server name
* @return the corresponding jetty server wrapped with its deployment
* properties.
*/
public ServerInstanceWrapper getServerInstanceWrapper(String managedServerName);
}

View File

@ -38,15 +38,10 @@ import org.osgi.framework.ServiceReference;
* webapps or ContextHandlers discovered from the OSGi environment.
*
*/
public class JettyServerServiceTracker implements ServiceListener, IManagedJettyServerRegistry
public class JettyServerServiceTracker implements ServiceListener
{
private static Logger LOG = Log.getLogger(JettyServerServiceTracker.class.getName());
/**
* Servers indexed by PIDs. PIDs are generated by the ConfigurationAdmin
* service.
*/
private Map<String, ServerInstanceWrapper> _serversIndexedByName = new HashMap<String, ServerInstanceWrapper>();
/** The context-handler to deactivate indexed by ServerInstanceWrapper */
private Map<ServiceReference, ServerInstanceWrapper> _indexByServiceReference = new HashMap<ServiceReference, ServerInstanceWrapper>();
@ -56,8 +51,7 @@ public class JettyServerServiceTracker implements ServiceListener, IManagedJetty
*/
public void stop()
{
// not sure that this is really useful but here we go.
for (ServerInstanceWrapper wrapper : _serversIndexedByName.values())
for (ServerInstanceWrapper wrapper : _indexByServiceReference.values())
{
try
{
@ -136,7 +130,6 @@ public class JettyServerServiceTracker implements ServiceListener, IManagedJetty
if (name == null) { throw new IllegalArgumentException("The property " + OSGiServerConstants.MANAGED_JETTY_SERVER_NAME + " is mandatory"); }
ServerInstanceWrapper wrapper = new ServerInstanceWrapper(name);
_indexByServiceReference.put(sr, wrapper);
_serversIndexedByName.put(name, wrapper);
return wrapper;
}
@ -151,25 +144,10 @@ public class JettyServerServiceTracker implements ServiceListener, IManagedJetty
ServerInstanceWrapper handler = _indexByServiceReference.remove(sr);
if (handler == null)
{
// a warning?
LOG.warn("Unknown Jetty Server ServiceReference: ", sr);
return null;
}
String name = handler.getManagedServerName();
if (name != null)
{
_serversIndexedByName.remove(name);
}
return handler;
}
/**
* @param managedServerName The server name
* @return the corresponding jetty server wrapped with its deployment
* properties.
*/
public ServerInstanceWrapper getServerInstanceWrapper(String managedServerName)
{
return _serversIndexedByName.get(managedServerName == null ? OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME : managedServerName);
}
}

View File

@ -45,10 +45,11 @@ import org.eclipse.jetty.osgi.boot.OSGiServerConstants;
import org.eclipse.jetty.osgi.boot.OSGiUndeployer;
import org.eclipse.jetty.osgi.boot.ServiceContextProvider;
import org.eclipse.jetty.osgi.boot.ServiceWebAppProvider;
import org.eclipse.jetty.osgi.boot.internal.webapp.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.osgi.boot.internal.webapp.LibExtClassLoaderHelper;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.osgi.boot.utils.FakeURLClassLoader;
import org.eclipse.jetty.osgi.boot.utils.TldBundleDiscoverer;
import org.eclipse.jetty.osgi.boot.utils.Util;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.util.IO;
@ -112,6 +113,87 @@ public class ServerInstanceWrapper
return __containerTldBundleDiscoverers;
}
/* ------------------------------------------------------------ */
public static Server configure(Server server, List<URL> jettyConfigurations, Dictionary props) throws Exception
{
if (jettyConfigurations == null || jettyConfigurations.isEmpty()) { return server; }
Map<String, Object> id_map = new HashMap<String, Object>();
if (server != null)
{
//Put in a mapping for the id "Server" and the name of the server as the instance being configured
id_map.put("Server", server);
id_map.put((String)props.get(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME), server);
}
Map<String, String> properties = new HashMap<String, String>();
if (props != null)
{
Enumeration<Object> en = props.keys();
while (en.hasMoreElements())
{
Object key = en.nextElement();
Object value = props.get(key);
String keyStr = String.valueOf(key);
String valStr = String.valueOf(value);
properties.put(keyStr, valStr);
if (server != null) server.setAttribute(keyStr, valStr);
}
}
for (URL jettyConfiguration : jettyConfigurations)
{
InputStream is = null;
try
{
// Execute a Jetty configuration file
Resource r = Resource.newResource(jettyConfiguration);
if (!r.exists())
{
LOG.warn("File does not exist "+r);
throw new IllegalStateException("No such jetty server config file: "+r);
}
is = r.getInputStream();
XmlConfiguration config = new XmlConfiguration(is);
config.getIdMap().putAll(id_map);
config.getProperties().putAll(properties);
// #334062 compute the URL of the folder that contains the
// conf file and set it as a property so we can compute relative paths
// from it.
String urlPath = jettyConfiguration.toString();
int lastSlash = urlPath.lastIndexOf('/');
if (lastSlash > 4)
{
urlPath = urlPath.substring(0, lastSlash);
config.getProperties().put(PROPERTY_THIS_JETTY_XML_FOLDER_URL, urlPath);
}
Object o = config.configure();
if (server == null)
server = (Server)o;
id_map = config.getIdMap();
}
catch (SAXParseException saxparse)
{
LOG.warn("Unable to configure the jetty/etc file " + jettyConfiguration, saxparse);
throw saxparse;
}
finally
{
IO.close(is);
}
}
return server;
}
/* ------------------------------------------------------------ */
@ -182,13 +264,16 @@ public class ServerInstanceWrapper
String sharedURLs = (String) props.get(OSGiServerConstants.MANAGED_JETTY_SHARED_LIB_FOLDER_URLS);
List<File> shared = sharedURLs != null ? extractFiles(sharedURLs) : null;
libExtClassLoader = LibExtClassLoaderHelper.createLibExtClassLoader(shared, null, server, JettyBootstrapActivator.class.getClassLoader());
libExtClassLoader = LibExtClassLoaderHelper.createLibExtClassLoader(shared, null,JettyBootstrapActivator.class.getClassLoader());
if (LOG.isDebugEnabled()) LOG.debug("LibExtClassLoader = "+libExtClassLoader);
Thread.currentThread().setContextClassLoader(libExtClassLoader);
configure(server, props);
String jettyConfigurationUrls = (String) props.get(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS);
List<URL> jettyConfigurations = jettyConfigurationUrls != null ? Util.fileNamesAsURLs(jettyConfigurationUrls, Util.DEFAULT_DELIMS) : null;
_server = configure(server, jettyConfigurations, props);
init();
@ -259,80 +344,6 @@ public class ServerInstanceWrapper
/* ------------------------------------------------------------ */
private void configure(Server server, Dictionary props) throws Exception
{
String jettyConfigurationUrls = (String) props.get(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS);
List<URL> jettyConfigurations = jettyConfigurationUrls != null ? extractResources(jettyConfigurationUrls) : null;
if (jettyConfigurations == null || jettyConfigurations.isEmpty()) { return; }
Map<String, Object> id_map = new HashMap<String, Object>();
//Put in a mapping for the id "Server" and the name of the server as the instance being configured
id_map.put("Server", server);
id_map.put((String)props.get(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME), server);
Map<String, String> properties = new HashMap<String, String>();
Enumeration<Object> en = props.keys();
while (en.hasMoreElements())
{
Object key = en.nextElement();
Object value = props.get(key);
String keyStr = String.valueOf(key);
String valStr = String.valueOf(value);
properties.put(keyStr, valStr);
server.setAttribute(keyStr, valStr);
}
for (URL jettyConfiguration : jettyConfigurations)
{
InputStream is = null;
try
{
// Execute a Jetty configuration file
Resource r = Resource.newResource(jettyConfiguration);
if (!r.exists())
{
LOG.warn("File does not exist "+r);
continue;
}
is = r.getInputStream();
XmlConfiguration config = new XmlConfiguration(is);
config.getIdMap().putAll(id_map);
// #334062 compute the URL of the folder that contains the
// jetty.xml conf file
// and set it as a property so we can compute relative paths
// from it.
String urlPath = jettyConfiguration.toString();
int lastSlash = urlPath.lastIndexOf('/');
if (lastSlash > 4)
{
urlPath = urlPath.substring(0, lastSlash);
Map<String, String> properties2 = new HashMap<String, String>(properties);
properties2.put(PROPERTY_THIS_JETTY_XML_FOLDER_URL, urlPath);
config.getProperties().putAll(properties2);
}
else
{
config.getProperties().putAll(properties);
}
config.configure();
id_map = config.getIdMap();
}
catch (SAXParseException saxparse)
{
LOG.warn("Unable to configure the jetty/etc file " + jettyConfiguration, saxparse);
throw saxparse;
}
finally
{
IO.close(is);
}
}
}
/* ------------------------------------------------------------ */
/**
* Must be called after the server is configured.
@ -432,54 +443,8 @@ public class ServerInstanceWrapper
}
}
/* ------------------------------------------------------------ */
/**
* @return The default folder in which the context files of the osgi bundles
* are located and watched. Or null when the system property
* "jetty.osgi.contexts.home" is not defined. If the configuration
* file defines the OSGiAppProvider's context. This will not be
* taken into account.
*/
File getDefaultOSGiContextsHome(File jettyHome)
{
String jettyContextsHome = System.getProperty("jetty.osgi.contexts.home");
if (jettyContextsHome != null)
{
File contextsHome = new File(jettyContextsHome);
if (!contextsHome.exists() || !contextsHome.isDirectory())
{
throw new IllegalArgumentException("the ${jetty.osgi.contexts.home} '"
+ jettyContextsHome
+ " must exist and be a folder");
}
return contextsHome;
}
return new File(jettyHome, "/contexts");
}
/* ------------------------------------------------------------ */
/**
* @return the urls in this string.
*/
private List<URL> extractResources(String propertyValue)
{
StringTokenizer tokenizer = new StringTokenizer(propertyValue, ",;", false);
List<URL> urls = new ArrayList<URL>();
while (tokenizer.hasMoreTokens())
{
String tok = tokenizer.nextToken();
try
{
urls.add(BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(new URL(tok)));
}
catch (Throwable mfe)
{
LOG.warn(mfe);
}
}
return urls;
}
/* ------------------------------------------------------------ */

View File

@ -84,7 +84,7 @@ public class LibExtClassLoaderHelper
* is the JettyBootStrapper (an osgi classloader.
* @throws MalformedURLException
*/
public static ClassLoader createLibEtcClassLoader(File jettyHome, Server server, ClassLoader parentClassLoader) throws MalformedURLException
public static ClassLoader createLibEtcClassLoader(File jettyHome, ClassLoader parentClassLoader) throws MalformedURLException
{
if (jettyHome == null) { return parentClassLoader; }
ArrayList<URL> urls = new ArrayList<URL>();
@ -141,7 +141,7 @@ public class LibExtClassLoaderHelper
* extra jars to insert, then just return the parentClassLoader.
* @throws MalformedURLException
*/
public static ClassLoader createLibExtClassLoader(List<File> jarsContainerOrJars, List<URL> otherJarsOrFolder, Server server, ClassLoader parentClassLoader)
public static ClassLoader createLibExtClassLoader(List<File> jarsContainerOrJars, List<URL> otherJarsOrFolder, ClassLoader parentClassLoader)
throws MalformedURLException
{
if (jarsContainerOrJars == null && otherJarsOrFolder == null) { return parentClassLoader; }

View File

@ -185,7 +185,6 @@ public class ServiceWatcher implements ServiceListener
try
{
added = e.getValue().serviceAdded(sr, contextHandler);
System.err.println(serverName+" deployed "+contextHandler+": "+added);
if (added && LOG.isDebugEnabled())
LOG.debug("Provider "+e.getValue()+" deployed "+contextHandler);
}

View File

@ -19,6 +19,7 @@
package org.eclipse.jetty.osgi.boot.utils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
@ -103,7 +104,7 @@ public interface BundleFileLocatorHelper
*
* @return a URL to the bundle entry that uses a common protocol
*/
public URL getLocalURL(URL url);
public URL getLocalURL(URL url) throws Exception;
/**
* Only useful for equinox: on felix we get the file:// url already. Other
@ -116,7 +117,9 @@ public interface BundleFileLocatorHelper
* @return a URL to the content of the bundle entry that uses the file:
* protocol
* </p>
* @throws IOException
* @throws Exception
*/
public URL getFileURL(URL url);
public URL getFileURL(URL url) throws Exception;
}

View File

@ -16,9 +16,8 @@
// ========================================================================
//
package org.eclipse.jetty.osgi.boot.internal.webapp;
package org.eclipse.jetty.osgi.boot.utils;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;

View File

@ -0,0 +1,118 @@
//
// ========================================================================
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.osgi.boot.utils;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.List;
import java.util.StringTokenizer;
/**
* Util
*
* Various useful functions used widely.
*/
public class Util
{
public static final String DEFAULT_DELIMS = ",;";
/* ------------------------------------------------------------ */
/**
* Treating the string as a separated list of filenames,
* convert and return the list of urls.
*
* @param val the separated list
* @param delims the separators (default is ,;)
* @return
* @throws MalformedURLException
*/
public static List<URL> fileNamesAsURLs(String val, String delims)
throws Exception
{
String separators = DEFAULT_DELIMS;
if (delims == null)
delims = separators;
StringTokenizer tokenizer = new StringTokenizer(val, delims, false);
List<URL> urls = new ArrayList<URL>();
while (tokenizer.hasMoreTokens())
{
urls.add(BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(new URL(tokenizer.nextToken())));
}
return urls;
}
/* ------------------------------------------------------------ */
public static void setProperty(Dictionary<String,String> properties, String key, String value)
{
if (value != null)
{
properties.put(key, value);
}
}
/* ------------------------------------------------------------ */
/**
* recursively substitute the ${sysprop} by their actual system property.
* ${sysprop,defaultvalue} will use 'defaultvalue' as the value if no
* sysprop is defined. Not the most efficient code but we are shooting for
* simplicity and speed of development here.
*
* @param value
* @return
*/
public static String resolvePropertyValue(String value)
{
int ind = value.indexOf("${");
if (ind == -1) { return value; }
int ind2 = value.indexOf('}', ind);
if (ind2 == -1) { return value; }
String sysprop = value.substring(ind + 2, ind2);
String defaultValue = null;
int comma = sysprop.indexOf(',');
if (comma != -1 && comma + 1 != sysprop.length())
{
defaultValue = sysprop.substring(comma + 1);
defaultValue = resolvePropertyValue(defaultValue);
sysprop = sysprop.substring(0, comma);
}
else
{
defaultValue = "${" + sysprop + "}";
}
String v = System.getProperty(sysprop);
String reminder = value.length() > ind2 + 1 ? value.substring(ind2 + 1) : "";
reminder = resolvePropertyValue(reminder);
if (v != null)
{
return value.substring(0, ind) + v + reminder;
}
else
{
return value.substring(0, ind) + defaultValue + reminder;
}
}
}

View File

@ -19,6 +19,7 @@
package org.eclipse.jetty.osgi.boot.utils.internal;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URI;
@ -301,25 +302,19 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
* @return a URL to the bundle entry that uses a common protocol
*/
public URL getLocalURL(URL url)
throws Exception
{
if ("bundleresource".equals(url.getProtocol()) || "bundleentry".equals(url.getProtocol()))
{
try
URLConnection conn = url.openConnection();
conn.setDefaultUseCaches(Resource.getDefaultUseCaches());
if (BUNDLE_URL_CONNECTION_getLocalURL == null && conn.getClass().getName().equals("org.eclipse.osgi.framework.internal.core.BundleURLConnection"))
{
URLConnection conn = url.openConnection();
conn.setDefaultUseCaches(Resource.getDefaultUseCaches());
if (BUNDLE_URL_CONNECTION_getLocalURL == null && conn.getClass().getName().equals("org.eclipse.osgi.framework.internal.core.BundleURLConnection"))
{
BUNDLE_URL_CONNECTION_getLocalURL = conn.getClass().getMethod("getLocalURL", null);
BUNDLE_URL_CONNECTION_getLocalURL.setAccessible(true);
}
if (BUNDLE_URL_CONNECTION_getLocalURL != null) { return (URL) BUNDLE_URL_CONNECTION_getLocalURL.invoke(conn, null); }
}
catch (Throwable t)
{
System.err.println("Unable to locate the OSGi url: '" + url + "'.");
t.printStackTrace();
BUNDLE_URL_CONNECTION_getLocalURL = conn.getClass().getMethod("getLocalURL", null);
BUNDLE_URL_CONNECTION_getLocalURL.setAccessible(true);
}
if (BUNDLE_URL_CONNECTION_getLocalURL != null) { return (URL) BUNDLE_URL_CONNECTION_getLocalURL.invoke(conn, null); }
}
return url;
}
@ -335,26 +330,23 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
* @return a URL to the content of the bundle entry that uses the file:
* protocol
* </p>
* @throws IOException
*/
public URL getFileURL(URL url)
public URL getFileURL(URL url) throws Exception
{
if ("bundleresource".equals(url.getProtocol()) || "bundleentry".equals(url.getProtocol()))
{
try
URLConnection conn = url.openConnection();
conn.setDefaultUseCaches(Resource.getDefaultUseCaches());
if (BUNDLE_URL_CONNECTION_getFileURL == null && conn.getClass().getName().equals("org.eclipse.osgi.framework.internal.core.BundleURLConnection"))
{
URLConnection conn = url.openConnection();
conn.setDefaultUseCaches(Resource.getDefaultUseCaches());
if (BUNDLE_URL_CONNECTION_getFileURL == null && conn.getClass().getName().equals("org.eclipse.osgi.framework.internal.core.BundleURLConnection"))
{
BUNDLE_URL_CONNECTION_getFileURL = conn.getClass().getMethod("getFileURL", null);
BUNDLE_URL_CONNECTION_getFileURL.setAccessible(true);
}
if (BUNDLE_URL_CONNECTION_getFileURL != null) { return (URL) BUNDLE_URL_CONNECTION_getFileURL.invoke(conn, null); }
}
catch (Throwable t)
{
t.printStackTrace();
BUNDLE_URL_CONNECTION_getFileURL = conn.getClass().getMethod("getFileURL", null);
BUNDLE_URL_CONNECTION_getFileURL.setAccessible(true);
}
if (BUNDLE_URL_CONNECTION_getFileURL != null) { return (URL) BUNDLE_URL_CONNECTION_getFileURL.invoke(conn, null); }
}
return url;
}

View File

@ -46,11 +46,30 @@ public class Activator implements BundleActivator
*/
public void start(BundleContext context) throws Exception
{
String serverName = "defaultJettyServer";
/* Uncomment to create a different server instance to deploy to. Also change
* TestJettyOSGiBootWebAppAsService to use the port 9999
Server server = new Server();
//do any setup on Server in here
serverName = "fooServer";
Dictionary serverProps = new Hashtable();
//define the unique name of the server instance
serverProps.put("managedServerName", serverName);
serverProps.put("jetty.port", "9999");
//let Jetty apply some configuration files to the Server instance
serverProps.put("jetty.etc.config.urls", "file:/opt/jetty/etc/jetty.xml,file:/opt/jetty/etc/jetty-selector.xml,file:/opt/jetty/etc/jetty-deployer.xml");
//register as an OSGi Service for Jetty to find
context.registerService(Server.class.getName(), server, serverProps);
*/
//Create a webapp context as a Service and target it at the Server created above
WebAppContext webapp = new WebAppContext();
Dictionary props = new Hashtable();
props.put("war",".");
props.put("contextPath","/acme");
//uiProps.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, serverName);
props.put("managedServerName", serverName);
context.registerService(ContextHandler.class.getName(),webapp,props);
}

View File

@ -0,0 +1,47 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<!-- ============================================================= -->
<!-- Configure a HTTPS connector. -->
<!-- This configuration must be used in conjunction with jetty.xml -->
<!-- and jetty-ssl.xml. -->
<!-- ============================================================= -->
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<!-- =========================================================== -->
<!-- Add a HTTPS Connector. -->
<!-- Configure an o.e.j.server.ServerConnector with connection -->
<!-- factories for TLS (aka SSL) and HTTP to provide HTTPS. -->
<!-- All accepted TLS connections are wired to a HTTP connection.-->
<!-- -->
<!-- Consult the javadoc of o.e.j.server.ServerConnector, -->
<!-- o.e.j.server.SslConnectionFactory and -->
<!-- o.e.j.server.HttpConnectionFactory for all configuration -->
<!-- that may be set here. -->
<!-- =========================================================== -->
<Call id="httpsConnector" name="addConnector">
<Arg>
<New class="org.eclipse.jetty.server.ServerConnector">
<Arg name="server"><Ref refid="Server" /></Arg>
<Arg name="factories">
<Array type="org.eclipse.jetty.server.ConnectionFactory">
<Item>
<New class="org.eclipse.jetty.server.SslConnectionFactory">
<Arg name="next">http/1.1</Arg>
<Arg name="sslContextFactory"><Ref refid="sslContextFactory"/></Arg>
</New>
</Item>
<Item>
<New class="org.eclipse.jetty.server.HttpConnectionFactory">
<Arg name="config"><Ref refid="sslHttpConfig"/></Arg>
</New>
</Item>
</Array>
</Arg>
<Set name="host"><Property name="jetty.host" /></Set>
<Set name="port"><Property name="jetty.https.port" default="8443" /></Set>
<Set name="idleTimeout">30000</Set>
</New>
</Arg>
</Call>
</Configure>

View File

@ -12,6 +12,15 @@
<Arg>
<New class="org.eclipse.jetty.server.ServerConnector">
<Arg><Ref refid="Server" /></Arg>
<Arg name="factories">
<Array type="org.eclipse.jetty.server.ConnectionFactory">
<Item>
<New class="org.eclipse.jetty.server.HttpConnectionFactory">
<Arg name="config"><Ref refid="httpConfig" /></Arg>
</New>
</Item>
</Array>
</Arg>
<Set name="host"><Property name="jetty.host" /></Set>
<Set name="port"><Property name="jetty.port" default="8080"/></Set>
<Set name="idleTimeout">300000</Set>

View File

@ -0,0 +1,41 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<!-- ============================================================= -->
<!-- Configure a TLS (SSL) Context Factory -->
<!-- This configuration must be used in conjunction with jetty.xml -->
<!-- and either jetty-https.xml or jetty-spdy.xml (but not both) -->
<!-- ============================================================= -->
<Configure id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory">
<Set name="KeyStorePath"><Property name="jetty.home" default="." />/<Property name="jetty.keystore" default="etc/keystore"/></Set>
<Set name="KeyStorePassword"><Property name="jetty.keystore.password" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set>
<Set name="KeyManagerPassword"><Property name="jetty.keymanager.password" default="OBF:1u2u1wml1z7s1z7a1wnl1u2g"/></Set>
<Set name="TrustStorePath"><Property name="jetty.home" default="." />/<Property name="jetty.truststore" default="etc/keystore"/></Set>
<Set name="TrustStorePassword"><Property name="jetty.truststore.password" default="OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4"/></Set>
<Set name="EndpointIdentificationAlgorithm"></Set>
<Set name="ExcludeCipherSuites">
<Array type="String">
<Item>SSL_RSA_WITH_DES_CBC_SHA</Item>
<Item>SSL_DHE_RSA_WITH_DES_CBC_SHA</Item>
<Item>SSL_DHE_DSS_WITH_DES_CBC_SHA</Item>
<Item>SSL_RSA_EXPORT_WITH_RC4_40_MD5</Item>
<Item>SSL_RSA_EXPORT_WITH_DES40_CBC_SHA</Item>
<Item>SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA</Item>
<Item>SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</Item>
</Array>
</Set>
<!-- =========================================================== -->
<!-- Create a TLS specific HttpConfiguration based on the -->
<!-- common HttpConfiguration defined in jetty.xml -->
<!-- Add a SecureRequestCustomizer to extract certificate and -->
<!-- session information -->
<!-- =========================================================== -->
<New id="sslHttpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
<Arg><Ref refid="httpConfig"/></Arg>
<Call name="addCustomizer">
<Arg><New class="org.eclipse.jetty.server.SecureRequestCustomizer"/></Arg>
</Call>
</New>
</Configure>

View File

@ -14,7 +14,7 @@
<!-- =========================================================== -->
<!-- Server Thread Pool -->
<!-- =========================================================== -->
<Arg name="threadPool">
<Arg name="threadpool">
<!-- Default queued blocking threadpool -->
<New class="org.eclipse.jetty.util.thread.QueuedThreadPool">
<Set name="minThreads">10</Set>
@ -44,6 +44,17 @@
</New>
</Set>
<New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
<Set name="secureScheme">https</Set>
<Set name="securePort"><Property name="jetty.secure.port" default="8443" /></Set>
<Set name="outputBufferSize">32768</Set>
<Set name="requestHeaderSize">8192</Set>
<Set name="responseHeaderSize">8192</Set>
<Set name="sendServerVersion">true</Set>
<Set name="sendDateHeader">false</Set>
<Set name="headerCacheSize">512</Set>
</New>
<!-- =========================================================== -->
<!-- extra options -->
@ -57,6 +68,20 @@
<!-- =========================================================== -->
<!-- jetty-jndi by default -->
<!-- =========================================================== -->
<Call class="org.eclipse.jetty.webapp.Configuration$ClassList" name="setServerDefault">
<Arg><Ref refid="Server" /></Arg>
<Call name="addAfter">
<Arg name="afterClass">org.eclipse.jetty.webapp.FragmentConfiguration</Arg>
<Arg>
<Array type="String">
<Item>org.eclipse.jetty.plus.webapp.EnvConfiguration</Item>
<Item>org.eclipse.jetty.plus.webapp.PlusConfiguration</Item>
<Item>org.eclipse.jetty.annotations.AnnotationConfiguration</Item>
</Array>
</Arg>
</Call>
</Call>
<Call class="java.lang.System" name="setProperty">
<Arg>java.naming.factory.initial</Arg>
<Arg><Property name="java.naming.factory.initial" default="org.eclipse.jetty.jndi.InitialContextFactory"/></Arg>

View File

@ -62,7 +62,7 @@ public class TestJettyOSGiBootCore
}
public static List<Option> provisionCoreJetty()
{
{
List<Option> res = new ArrayList<Option>();
// get the jetty home config from the osgi boot bundle.
res.add(CoreOptions.systemProperty("jetty.port").value(String.valueOf(DEFAULT_JETTY_HTTP_PORT)));
@ -96,7 +96,6 @@ public class TestJettyOSGiBootCore
res.add(mavenBundle().groupId( "org.eclipse.jetty.websocket" ).artifactId( "websocket-common" ).versionAsInProject().noStart());
res.add(mavenBundle().groupId( "org.eclipse.jetty.websocket" ).artifactId( "websocket-servlet" ).versionAsInProject().noStart());
res.add(mavenBundle().groupId( "org.eclipse.jetty.websocket" ).artifactId( "websocket-server" ).versionAsInProject().noStart());
return res;
}

View File

@ -61,8 +61,9 @@ public class TestJettyOSGiBootSpdy
TestOSGiUtil.addMoreOSGiContainers(options);
options.addAll(TestJettyOSGiBootCore.provisionCoreJetty());
options.addAll(TestJettyOSGiBootWithJsp.configureJettyHomeAndPort("jetty-spdy.xml"));
options.addAll(TestJettyOSGiBootCore.coreJettyDependencies());
options.add(CoreOptions.junitBundles());
options.addAll(TestJettyOSGiBootCore.httpServiceJetty());
options.addAll(spdyJettyDependencies());

View File

@ -148,7 +148,6 @@ public class TestJettyOSGiBootWebAppAsService
@Test
public void testBundle() throws Exception
{
// now test the jsp/dump.jsp
HttpClient client = new HttpClient();
try

View File

@ -118,9 +118,14 @@ public class TestJettyOSGiBootWithJsp
+ jettySelectorFileName
+ ";"
+ etc
+ "/jetty-ssl.xml;"
+ etc
+ "/jetty-https.xml;"
+ etc
+ "/jetty-deployer.xml;"
+ etc
+ "/jetty-testrealm.xml";
options.add(systemProperty(OSGiServerConstants.MANAGED_JETTY_XML_CONFIG_URLS).value(xmlConfigs));
options.add(systemProperty("jetty.port").value(String.valueOf(TestJettyOSGiBootCore.DEFAULT_JETTY_HTTP_PORT)));
options.add(systemProperty("jetty.home").value(etcFolder.getParentFile().getAbsolutePath()));

View File

@ -50,13 +50,15 @@ public class TestOSGiUtil
* Note: this will run many more tests. TODO: find a better way to control
* this and use non-deprecated methods.
*
* @param options
* @param opti
*/
protected static void addMoreOSGiContainers(List<Option> options)
{
options.add(CoreOptions.equinox().version("3.6.1"));
options.add(CoreOptions.equinox().version("3.7.0"));
options.add(CoreOptions.felix().version("3.2.2"));
//Uncomment to run more containers - these have been commented out
//to improve speed of builds.
//options.add(CoreOptions.equinox().version("3.6.1"));
//options.add(CoreOptions.equinox().version("3.7.0"));
// options.add(CoreOptions.felix().version("3.2.2"));
options.add(CoreOptions.felix().version("4.0.2"));
}

View File

@ -623,6 +623,7 @@ public class HttpChannel<T> implements HttpParser.RequestHandler<T>, Runnable
protected boolean sendResponse(ResponseInfo info, ByteBuffer content, boolean complete, final Callback callback)
{
// TODO check that complete only set true once by changing _committed to AtomicRef<Enum>
boolean committing = _committed.compareAndSet(false, true);
if (committing)
{

View File

@ -106,6 +106,17 @@ write completed - - - ASYNC READY->owp
public boolean isAllContentWritten()
{
return _channel.getResponse().isAllContentWritten(_written);
{
try
{
_channel.getResponse().closeOutput();
}
catch(IOException e)
{
_channel.getEndPoint().shutdownOutput();
LOG.ignore(e);
}
}
}
@Override
@ -305,6 +316,8 @@ write completed - - - ASYNC READY->owp
// write any remaining content in the buffer directly
if (len>0)
_channel.write(ByteBuffer.wrap(b, off, len), complete);
else if (complete)
_channel.write(BufferUtil.EMPTY_BUFFER,complete);
if (complete)
{
@ -441,9 +454,23 @@ write completed - - - ASYNC READY->owp
* @param content The content to send
* @param callback The callback to use to notify success or failure
*/
public void sendContent(ByteBuffer content, Callback callback)
public void sendContent(ByteBuffer content, final Callback callback)
{
_channel.write(content,true,callback);
_channel.write(content,true,new Callback()
{
@Override
public void succeeded()
{
closed();
callback.succeeded();
}
@Override
public void failed(Throwable x)
{
callback.failed(x);
}
});
}
/* ------------------------------------------------------------ */
@ -493,7 +520,6 @@ write completed - - - ASYNC READY->owp
}
break;
}
ByteBuffer buffer= _channel.useDirectBuffers()?httpContent.getDirectBuffer():null;
if (buffer == null)
buffer = httpContent.getIndirectBuffer();
@ -750,6 +776,7 @@ write completed - - - ASYNC READY->owp
int len=_in.read(_buffer.array(),0,_buffer.capacity());
if (len==-1)
{
closed();
_channel.getByteBufferPool().release(_buffer);
return true;
}
@ -808,6 +835,7 @@ write completed - - - ASYNC READY->owp
int len=_in.read(_buffer);
if (len==-1)
{
closed();
_channel.getByteBufferPool().release(_buffer);
return true;
}

View File

@ -547,7 +547,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
_contextAttributeListeners.clear();
_requestListeners.clear();
_requestAttributeListeners.clear();
_eventListeners.clear();
if (eventListeners!=null)
for (EventListener listener : eventListeners)
addEventListener(listener);

View File

@ -66,22 +66,31 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
doCompress();
}
/* ------------------------------------------------------------ */
/**
* Reset buffer.
*/
public void resetBuffer()
{
if (_response.isCommitted())
if (_response.isCommitted() || _compressedOutputStream!=null )
throw new IllegalStateException("Committed");
_closed = false;
_out = null;
_bOut = null;
if (_compressedOutputStream != null)
_response.setHeader("Content-Encoding",null);
_compressedOutputStream = null;
_doNotCompress = false;
}
/* ------------------------------------------------------------ */
public void setBufferSize(int bufferSize)
{
if (_bOut!=null && _bOut.getBuf().length<bufferSize)
{
ByteArrayOutputStream2 b = new ByteArrayOutputStream2(bufferSize);
b.write(_bOut.getBuf(),0,_bOut.size());
_bOut=b;
}
}
/* ------------------------------------------------------------ */
public void setContentLength()
{
@ -171,7 +180,7 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
if (_out == null || _bOut != null)
{
long length=_wrapper.getContentLength();
if (length > 0 && length < _wrapper.getMinCompressSize())
if (length<0 && _bOut==null || length >= 0 && length < _wrapper.getMinCompressSize())
doNotCompress(false);
else
doCompress();
@ -375,4 +384,5 @@ public abstract class AbstractCompressedStream extends ServletOutputStream
*/
protected abstract DeflaterOutputStream createStream() throws IOException;
}

View File

@ -108,6 +108,8 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
public void setBufferSize(int bufferSize)
{
_bufferSize = bufferSize;
if (_compressedStream!=null)
_compressedStream.setBufferSize(bufferSize);
}
/* ------------------------------------------------------------ */
@ -128,7 +130,7 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
{
super.setContentType(ct);
if (_compressedStream==null || _compressedStream.getOutputStream()==null)
if (!_noCompression && (_compressedStream==null || _compressedStream.getOutputStream()==null))
{
if (ct!=null)
{
@ -174,7 +176,10 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
@Override
public void setContentLength(int length)
{
setContentLength((long)length);
if (_noCompression)
super.setContentLength(length);
else
setContentLength((long)length);
}
/* ------------------------------------------------------------ */
@ -312,6 +317,8 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
*/
public void noCompression()
{
if (!_noCompression)
setDeferredHeaders();
_noCompression=true;
if (_compressedStream!=null)
{
@ -336,6 +343,25 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
_writer.flush();
if (_compressedStream!=null)
_compressedStream.finish();
else
setDeferredHeaders();
}
/* ------------------------------------------------------------ */
private void setDeferredHeaders()
{
if (!isCommitted())
{
if (_contentLength>=0)
{
if (_contentLength < Integer.MAX_VALUE)
super.setContentLength((int)_contentLength);
else
super.setHeader("Content-Length",Long.toString(_contentLength));
}
if(_etag!=null)
super.setHeader("ETag",_etag);
}
}
/* ------------------------------------------------------------ */
@ -345,7 +371,9 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
@Override
public void setHeader(String name, String value)
{
if ("content-length".equalsIgnoreCase(name))
if (_noCompression)
super.setHeader(name,value);
else if ("content-length".equalsIgnoreCase(name))
{
setContentLength(Long.parseLong(value));
}
@ -371,7 +399,7 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
@Override
public boolean containsHeader(String name)
{
if ("etag".equalsIgnoreCase(name) && _etag!=null)
if (!_noCompression && "etag".equalsIgnoreCase(name) && _etag!=null)
return true;
return super.containsHeader(name);
}
@ -386,10 +414,7 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
if (_compressedStream==null)
{
if (getResponse().isCommitted() || _noCompression)
{
setContentLength(_contentLength);
return getResponse().getOutputStream();
}
_compressedStream=newCompressedStream(_request,(HttpServletResponse)getResponse());
}
@ -412,10 +437,7 @@ public abstract class CompressedResponseWrapper extends HttpServletResponseWrapp
throw new IllegalStateException("getOutputStream() called");
if (getResponse().isCommitted() || _noCompression)
{
setContentLength(_contentLength);
return getResponse().getWriter();
}
_compressedStream=newCompressedStream(_request,(HttpServletResponse)getResponse());
_writer=newWriter(_compressedStream,getCharacterEncoding());

View File

@ -25,6 +25,7 @@ import java.util.List;
import javax.servlet.Servlet;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper;
import org.eclipse.jetty.servlets.gzip.GzipTester;
@ -35,6 +36,8 @@ import org.eclipse.jetty.servlets.gzip.TestServletStreamTypeLengthWrite;
import org.eclipse.jetty.servlets.gzip.TestServletTypeLengthStreamWrite;
import org.eclipse.jetty.servlets.gzip.TestServletTypeStreamLengthWrite;
import org.eclipse.jetty.toolchain.test.TestingDir;
import org.hamcrest.Matchers;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@ -132,7 +135,8 @@ public class GzipFilterContentLengthTest
try
{
tester.start();
tester.assertIsResponseNotGzipCompressed("GET",testfile.getName(),filesize,HttpStatus.OK_200);
HttpTester.Response response = tester.assertIsResponseNotGzipCompressed("GET",testfile.getName(),filesize,HttpStatus.OK_200);
Assert.assertThat(response.get("ETAG"),Matchers.startsWith("W/etag-"));
}
finally
{
@ -140,6 +144,15 @@ public class GzipFilterContentLengthTest
}
}
/**
* Tests gzip compression of a small size file
*/
@Test
public void testEmpty() throws Exception
{
assertIsNotGzipCompressed("empty.txt",0);
}
/**
* Tests gzip compression of a small size file
*/

View File

@ -79,6 +79,7 @@ public class GzipFilterDefaultTest
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
resp.setStatus(_status);
resp.setHeader("ETag","W/\"204\"");
}
}
@ -141,11 +142,40 @@ public class GzipFilterDefaultTest
@Override
public void service(HttpServletRequest req, HttpServletResponse resp) throws IOException,ServletException
{
String uri=req.getRequestURI();
if (uri.endsWith(".deferred"))
{
System.err.println("type for "+uri.substring(0,uri.length()-9)+" is "+getServletContext().getMimeType(uri.substring(0,uri.length()-9)));
resp.setContentType(getServletContext().getMimeType(uri.substring(0,uri.length()-9)));
}
doGet(req,resp);
}
}
@Test
public void testIsGzipCompressedEmpty() throws Exception
{
GzipTester tester = new GzipTester(testingdir, compressionType);
// Test content that is smaller than the buffer.
tester.prepareServerFile("empty.txt",0);
FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class);
holder.setInitParameter("mimeTypes","text/plain");
try
{
tester.start();
HttpTester.Response http = tester.assertIsResponseNotGzipCompressed("GET","empty.txt",0,200);
}
finally
{
tester.stop();
}
}
@Test
public void testIsGzipCompressedTiny() throws Exception
@ -267,7 +297,7 @@ public class GzipFilterDefaultTest
}
@Test
public void testIsNotGzipCompressed() throws Exception
public void testIsNotGzipCompressedByContentType() throws Exception
{
GzipTester tester = new GzipTester(testingdir, compressionType);
@ -289,6 +319,29 @@ public class GzipFilterDefaultTest
}
}
@Test
public void testIsNotGzipCompressedByDeferredContentType() throws Exception
{
GzipTester tester = new GzipTester(testingdir, compressionType);
int filesize = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE * 4;
tester.prepareServerFile("file.mp3.deferred",filesize);
FilterHolder holder = tester.setContentServlet(GetServlet.class);
holder.setInitParameter("mimeTypes","text/plain");
try
{
tester.start();
HttpTester.Response http = tester.assertIsResponseNotGzipCompressed("GET","file.mp3.deferred", filesize, HttpStatus.OK_200);
Assert.assertNull(http.get("Vary"));
}
finally
{
tester.stop();
}
}
@Test
public void testIsNotGzipCompressedHttpStatus() throws Exception
{

View File

@ -1,258 +0,0 @@
//
// ========================================================================
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.servlets;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.security.DigestOutputStream;
import java.security.MessageDigest;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.zip.GZIPInputStream;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;
import javax.servlet.DispatcherType;
import org.eclipse.jetty.server.NetworkConnector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlets.gzip.Hex;
import org.eclipse.jetty.servlets.gzip.NoOpOutputStream;
import org.eclipse.jetty.toolchain.test.IO;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.TestingDir;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
/**
* Test the effects of Gzip filtering when in the context of HTTP/1.1 Pipelining.
*/
@RunWith(Parameterized.class)
public class GzipWithPipeliningTest
{
@Parameters
public static Collection<String[]> data()
{
// Test different Content-Encoding header combinations. So implicitly testing that gzip is preferred oder deflate
String[][] data = new String[][]
{
{ GzipFilter.GZIP },
{ GzipFilter.DEFLATE + ", " + GzipFilter.GZIP },
{ GzipFilter.GZIP + ", " + GzipFilter.DEFLATE },
{ GzipFilter.DEFLATE }
};
return Arrays.asList(data);
}
@Rule
public TestingDir testingdir = new TestingDir();
private Server server;
private URI serverUri;
private String encodingHeader;
public GzipWithPipeliningTest(String encodingHeader)
{
this.encodingHeader = encodingHeader;
}
@Before
public void startServer() throws Exception
{
// Configure Server
server = new Server(0);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
DefaultServlet servlet = new DefaultServlet();
ServletHolder holder = new ServletHolder(servlet);
holder.setInitParameter("resourceBase",MavenTestingUtils.getTestResourcesDir().getAbsolutePath());
context.addServlet(holder,"/");
FilterHolder filter = context.addFilter(GzipFilter.class,"/*", EnumSet.of(DispatcherType.REQUEST));
filter.setInitParameter("mimeTypes","text/plain");
server.setHandler(context);
// Start Server
server.start();
serverUri = server.getURI();
}
@After
public void stopServer() throws Exception
{
server.stop();
}
@Test
public void testGzipThenImagePipelining() throws Exception
{
testingdir.ensureEmpty();
File outputDir = testingdir.getDir();
PipelineHelper client = new PipelineHelper(serverUri, encodingHeader);
try
{
File txtFile = MavenTestingUtils.getTestResourceFile("lots-of-fantasy-names.txt");
File pngFile = MavenTestingUtils.getTestResourceFile("jetty_logo.png");
// Size of content, as it exists on disk, without gzip compression.
long rawsize = txtFile.length() + pngFile.length();
assertThat("Ensure that we have sufficient file size to trigger chunking",rawsize,greaterThan(300000L));
String respHeader;
client.connect();
// Request text that will be gzipped + chunked in the response
client.issueGET("/lots-of-fantasy-names.txt",true, false);
respHeader = client.readResponseHeader();
//System.out.println("Response Header #1 --\n" + respHeader);
String expectedEncodingHeader = encodingHeader.equals(GzipFilter.DEFLATE) ? GzipFilter.DEFLATE : GzipFilter.GZIP;
assertThat("Content-Encoding should be gzipped",respHeader,containsString("Content-Encoding: " + expectedEncodingHeader + "\r\n"));
assertThat("Transfer-Encoding should be chunked",respHeader,containsString("Transfer-Encoding: chunked\r\n"));
// Raw output / gzipped, writted to disk (checked for sha1sum later)
File rawOutputFile = new File(outputDir, "response-1.gz");
FileOutputStream rawOutputStream = new FileOutputStream(rawOutputFile);
long chunkSize = client.readChunkSize();
//System.out.println("Chunk Size: " + chunkSize);
// Read only 20% - intentionally a partial read.
//System.out.println("Attempting to read partial content ...");
int readBytes = client.readBody(rawOutputStream,(int)(chunkSize * 0.20f));
//System.out.printf("Read %,d bytes%n",readBytes);
// Issue another request
client.issueGET("/jetty_logo.png",true, false);
// Finish reading chunks
//System.out.println("Finish reading remaining chunks ...");
String line;
chunkSize = chunkSize - readBytes;
while (chunkSize > 0)
{
readBytes = client.readBody(rawOutputStream,(int)chunkSize);
//System.out.printf("Read %,d bytes%n",readBytes);
line = client.readLine();
assertThat("Chunk delim should be an empty line with CR+LF",line,is(""));
chunkSize = client.readChunkSize();
//System.out.printf("Next Chunk: (0x%X) %,d bytes%n",chunkSize,chunkSize);
}
// Inter-pipeline delim
line = client.readLine();
assertThat("Inter-pipeline delim should be an empty line with CR+LF",line,is(""));
// Sha1tracking for 1st Request
MessageDigest digestTxt = MessageDigest.getInstance("SHA1");
DigestOutputStream digesterTxt = new DigestOutputStream(new NoOpOutputStream(),digestTxt);
// Decompress 1st request and calculate sha1sum
IO.close(rawOutputStream);
FileInputStream rawInputStream = new FileInputStream(rawOutputFile);
InputStream uncompressedStream = null;
if (GzipFilter.DEFLATE.equals(encodingHeader))
{
uncompressedStream = new InflaterInputStream(rawInputStream, new Inflater(true));
}
else
{
uncompressedStream = new GZIPInputStream(rawInputStream);
}
IO.copy(uncompressedStream, digesterTxt);
// Read 2nd request http response header
respHeader = client.readResponseHeader();
//System.out.println("Response Header #2 --\n" + respHeader);
assertThat("Content-Encoding should NOT be gzipped",respHeader,not(containsString("Content-Encoding: gzip\r\n")));
assertThat("Transfer-Encoding should NOT be chunked",respHeader,not(containsString("Transfer-Encoding: chunked\r\n")));
// Sha1tracking for 2nd Request
MessageDigest digestImg = MessageDigest.getInstance("SHA1");
DigestOutputStream digesterImg = new DigestOutputStream(new NoOpOutputStream(),digestImg);
// Read 2nd request body
int contentLength = client.getContentLength(respHeader);
assertThat("Image Content Length",(long)contentLength,is(pngFile.length()));
client.readBody(digesterImg,contentLength);
// Validate checksums
IO.close(rawOutputStream);
assertChecksum("lots-of-fantasy-names.txt",digestTxt);
IO.close(digesterImg);
assertChecksum("jetty_logo.png",digestImg);
}
finally
{
client.disconnect();
}
}
private void assertChecksum(String testResourceFile, MessageDigest digest) throws IOException
{
String expectedSha1 = loadSha1sum(testResourceFile + ".sha1");
String actualSha1 = Hex.asHex(digest.digest());
assertEquals(testResourceFile + " / SHA1Sum of content",expectedSha1,actualSha1);
}
private String loadSha1sum(String testResourceSha1Sum) throws IOException
{
File sha1File = MavenTestingUtils.getTestResourceFile(testResourceSha1Sum);
String contents = IO.readToString(sha1File);
Pattern pat = Pattern.compile("^[0-9A-Fa-f]*");
Matcher mat = pat.matcher(contents);
assertTrue("Should have found HEX code in SHA1 file: " + sha1File,mat.find());
return mat.group();
}
}

View File

@ -55,6 +55,7 @@ import org.eclipse.jetty.servlets.GzipFilter;
import org.eclipse.jetty.toolchain.test.IO;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.TestingDir;
import org.hamcrest.Matchers;
import org.junit.Assert;
public class GzipTester
@ -105,6 +106,8 @@ public class GzipTester
else
Assert.assertThat("Response.header[Content-Encoding]", response.get("Content-Encoding"),containsString(compressionType.substring(0,qindex)));
Assert.assertThat(response.get("ETag"),Matchers.startsWith("W/"));
// Assert that the decompressed contents are what we expect.
File serverFile = testdir.getFile(serverFilename);
String expected = IO.readToString(serverFile);
@ -182,6 +185,8 @@ public class GzipTester
Assert.assertThat(prefix + ".header[Content-Type] (should have a Content-Type associated with it)",response.get("Content-Type"),notNullValue());
Assert.assertThat(prefix + ".header[Content-Type]",response.get("Content-Type"),is(expectedContentType));
Assert.assertThat(response.get("ETAG"),Matchers.startsWith("W/"));
ByteArrayInputStream bais = null;
DigestOutputStream digester = null;
try
@ -308,6 +313,10 @@ public class GzipTester
int serverLength = Integer.parseInt(response.get("Content-Length"));
Assert.assertEquals(serverLength,expectedFilesize);
}
if (status>=200 && status<300)
Assert.assertThat(response.get("ETAG"),Matchers.startsWith("W/"));
}
Assert.assertThat("Response.header[Content-Encoding]",response.get("Content-Encoding"),not(containsString(compressionType)));
}
@ -337,11 +346,11 @@ public class GzipTester
ByteArrayOutputStream out = null;
try
{
in = new ByteArrayInputStream(response.getContentBytes());
out = new ByteArrayOutputStream();
IO.copy(in,out);
actual = out.toString(encoding);
byte[] content=response.getContentBytes();
if (content!=null)
actual=new String(response.getContentBytes(),encoding);
else
actual="";
}
finally
{
@ -424,7 +433,7 @@ public class GzipTester
finally
{
IO.close(in);
IO.close(fos);
IO.close(fos);
}
}
@ -456,6 +465,7 @@ public class GzipTester
tester.setResourceBase(testdir.getDir().getCanonicalPath());
ServletHolder servletHolder = tester.addServlet(servletClass,"/");
servletHolder.setInitParameter("baseDir",testdir.getDir().getAbsolutePath());
servletHolder.setInitParameter("etags","true");
FilterHolder holder = tester.addFilter(gzipFilterClass,"/*",EnumSet.allOf(DispatcherType.class));
holder.setInitParameter("vary","Accept-Encoding");
return holder;

View File

@ -50,6 +50,7 @@ public class TestMinGzipSizeServlet extends TestDirContentServlet
byte[] dataBytes = loadContentFileBytes(fileName);
response.setContentLength(dataBytes.length);
response.setHeader("ETag","W/etag-"+fileName);
if (fileName.endsWith(".js"))
{
// intentionally long-form content type to test ";" splitting in code

View File

@ -59,6 +59,7 @@ public class TestServletLengthStreamTypeWrite extends TestDirContentServlet
response.setContentType("text/plain");
else if (fileName.endsWith("mp3"))
response.setContentType("audio/mpeg");
response.setHeader("ETag","W/etag-"+fileName);
out.write(dataBytes);
}

View File

@ -57,6 +57,7 @@ public class TestServletLengthTypeStreamWrite extends TestDirContentServlet
response.setContentType("text/plain");
else if (fileName.endsWith("mp3"))
response.setContentType("audio/mpeg");
response.setHeader("ETag","W/etag-"+fileName);
ServletOutputStream out = response.getOutputStream();
out.write(dataBytes);

View File

@ -59,6 +59,7 @@ public class TestServletStreamLengthTypeWrite extends TestDirContentServlet
response.setContentType("text/plain");
else if (fileName.endsWith("mp3"))
response.setContentType("audio/mpeg");
response.setHeader("ETag","W/etag-"+fileName);
out.write(dataBytes);
}

View File

@ -57,6 +57,7 @@ public class TestServletStreamTypeLengthWrite extends TestDirContentServlet
response.setContentType("text/plain");
else if (fileName.endsWith("mp3"))
response.setContentType("audio/mpeg");
response.setHeader("ETag","W/etag-"+fileName);
response.setContentLength(dataBytes.length);

View File

@ -55,6 +55,7 @@ public class TestServletTypeLengthStreamWrite extends TestDirContentServlet
response.setContentType("text/plain");
else if (fileName.endsWith("mp3"))
response.setContentType("audio/mpeg");
response.setHeader("ETag","W/etag-"+fileName);
response.setContentLength(dataBytes.length);

View File

@ -55,6 +55,7 @@ public class TestServletTypeStreamLengthWrite extends TestDirContentServlet
response.setContentType("text/plain");
else if (fileName.endsWith("mp3"))
response.setContentType("audio/mpeg");
response.setHeader("ETag","W/etag-"+fileName);
ServletOutputStream out = response.getOutputStream();

View File

@ -67,6 +67,7 @@ public class TestStaticMimeTypeServlet extends TestDirContentServlet
byte[] dataBytes = loadContentFileBytes(fileName);
response.setContentLength(dataBytes.length);
response.setHeader("ETag","W/etag-"+fileName);
String mime = mimeTypes.getMimeByExtension(fileName);
if (mime == null)