Merge remote-tracking branch 'origin/master' into jetty-8

Conflicts:
	jetty-npn/pom.xml
	jetty-osgi/jetty-osgi-boot-jsp/META-INF/MANIFEST.MF
	jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/WebappRegistrationCustomizerImpl.java
	jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jsp/FragmentActivator.java
	jetty-osgi/jetty-osgi-boot-logback/META-INF/MANIFEST.MF
	jetty-osgi/jetty-osgi-boot-warurl/META-INF/MANIFEST.MF
	jetty-osgi/jetty-osgi-boot/META-INF/MANIFEST.MF
	jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebBundleDeployerHelper.java
	jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebBundleTrackerCustomizer.java
	jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java
	jetty-osgi/jetty-osgi-equinoxtools/META-INF/MANIFEST.MF
	jetty-osgi/jetty-osgi-httpservice/META-INF/MANIFEST.MF
	jetty-spdy/spdy-jetty-http-webapp/pom.xml
	jetty-spdy/spdy-jetty-http/pom.xml
	jetty-spdy/spdy-jetty/pom.xml
This commit is contained in:
Greg Wilkins 2012-04-12 16:02:34 +10:00
commit ee2d289f63
57 changed files with 2121 additions and 1944 deletions

View File

@ -878,7 +878,7 @@ public class HttpClient extends AggregateLifeCycle implements HttpBuffers, Attri
@Deprecated
public void setProvider(String provider)
{
setProvider(provider);
_sslContextFactory.setProvider(provider);
}
/* ------------------------------------------------------------ */

View File

@ -260,7 +260,6 @@ public class HttpParser implements Parser
{
_state=STATE_END;
_handler.messageComplete(_contentPosition);
returnBuffers();
return 1;
}
@ -326,7 +325,6 @@ public class HttpParser implements Parser
if (!isComplete() && !isIdle())
throw new EofException();
returnBuffers();
return -1;
}
length=_buffer.length();
@ -440,7 +438,6 @@ public class HttpParser implements Parser
_state=STATE_SEEKING_EOF;
_handler.headerComplete();
_handler.messageComplete(_contentPosition);
returnBuffers();
return 1;
}
break;
@ -470,7 +467,6 @@ public class HttpParser implements Parser
_state=STATE_SEEKING_EOF;
_handler.headerComplete();
_handler.messageComplete(_contentPosition);
returnBuffers();
return 1;
}
}
@ -634,7 +630,6 @@ public class HttpParser implements Parser
_handler.headerComplete();
_state=_persistent||(_responseStatus>=100&&_responseStatus<200)?STATE_END:STATE_SEEKING_EOF;
_handler.messageComplete(_contentPosition);
returnBuffers();
return 1;
default:
@ -840,7 +835,6 @@ public class HttpParser implements Parser
{
_state=_persistent?STATE_END:STATE_SEEKING_EOF;
_handler.messageComplete(_contentPosition);
returnBuffers();
return 1;
}
@ -860,7 +854,6 @@ public class HttpParser implements Parser
{
_state=_persistent?STATE_END:STATE_SEEKING_EOF;
_handler.messageComplete(_contentPosition);
returnBuffers();
}
// TODO adjust the _buffer to keep unconsumed content
return 1;
@ -895,7 +888,6 @@ public class HttpParser implements Parser
_eol=_buffer.get();
_state=_persistent?STATE_END:STATE_SEEKING_EOF;
_handler.messageComplete(_contentPosition);
returnBuffers();
return 1;
}
else
@ -926,7 +918,6 @@ public class HttpParser implements Parser
_eol=_buffer.get();
_state=_persistent?STATE_END:STATE_SEEKING_EOF;
_handler.messageComplete(_contentPosition);
returnBuffers();
return 1;
}
else

View File

@ -13,8 +13,6 @@
package org.eclipse.jetty.http.gzip;
import java.io.Closeable;
import java.io.Flushable;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
@ -32,7 +30,7 @@ import org.eclipse.jetty.util.ByteArrayOutputStream2;
/**
* Skeletal implementation of a CompressedStream. This class adds compression features to a ServletOutputStream and takes care of setting response headers, etc.
* Major work and configuration is done here. Subclasses using different kinds of compression only have to implement the abstract methods doCompress() and
* setContentEncoding() using the desired compression and setting the appropiate Content-Encoding header string.
* setContentEncoding() using the desired compression and setting the appropriate Content-Encoding header string.
*/
public abstract class AbstractCompressedStream extends ServletOutputStream
{

View File

@ -2,13 +2,35 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-project</artifactId>
<version>8.1.3-SNAPSHOT</version>
<artifactId>jetty-parent</artifactId>
<version>19</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.eclipse.jetty.npn</groupId>
<artifactId>npn-api</artifactId>
<version>1.0.1-SNAPSHOT</version>
<name>Jetty :: Next Protocol Negotiation :: API</name>
<scm>
<connection>scm:git:http://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project.git</connection>
<developerConnection>scm:git:ssh://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project.git</developerConnection>
<url>http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/jetty-npn</url>
</scm>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.2.1</version>
<configuration>
<useReleaseProfile>false</useReleaseProfile>
<goals>deploy</goals>
<arguments>-Peclipse-release</arguments>
<preparationGoals>clean install</preparationGoals>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -28,27 +28,31 @@ import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;
/**
* Plug bundles that contains tld files so that jasper will discover them
* and set them up in jetty.
* Plug bundles that contains tld files so that jasper will discover them and
* set them up in jetty.
*
* For example: -Dorg.eclipse.jetty.osgi.tldbundles=org.springframework.web.servlet,com.opensymphony.module.sitemesh
* Otherwise use an attribute to the WebAppDeployer
* &lt;New class="org.eclipse.jetty.deploy.providers.WebAppProvider"&gt;
* ....
* &lt;Set name="tldBundles"&gt;&ltProperty name="org.eclipse.jetty.osgi.tldsbundles" default="" /&gt;&lt;/Set&gt;
* &lt;New&gt;
* For example:
* -Dorg.eclipse.jetty.osgi.tldbundles=org.springframework.web.servlet
* ,com.opensymphony.module.sitemesh Otherwise use an attribute to the
* WebAppDeployer &lt;New
* class="org.eclipse.jetty.deploy.providers.WebAppProvider"&gt; .... &lt;Set
* name="tldBundles"&gt;&ltProperty name="org.eclipse.jetty.osgi.tldsbundles"
* default="" /&gt;&lt;/Set&gt; &lt;New&gt;
*/
public class PluggableWebAppRegistrationCustomizerImpl implements WebappRegistrationCustomizer
{
/**
* To plug into jasper bundles that contain tld files
* please use a list of bundle's symbolic names:
* -Djetty.osgi.tldbundles=org.springframework.web.servlet,com.opensymphony.module.sitemesh
* To plug into jasper bundles that contain tld files please use a list of
* bundle's symbolic names:
* -Djetty.osgi.tldbundles=org.springframework.web.servlet
* ,com.opensymphony.module.sitemesh
*/
public static final String SYS_PROP_TLD_BUNDLES = "org.eclipse.jetty.osgi.tldbundles";
/**
* Union of the tld bundles defined system wide and the one defines as an attribute of the AppProvider.
* Union of the tld bundles defined system wide and the one defines as an
* attribute of the AppProvider.
*
* @param provider
* @return
*/
@ -56,10 +60,7 @@ public class PluggableWebAppRegistrationCustomizerImpl implements WebappRegistra
{
String sysprop = System.getProperty(SYS_PROP_TLD_BUNDLES);
String att = (String) provider.getTldBundles();
if (sysprop == null && att == null)
{
return Collections.emptySet();
}
if (sysprop == null && att == null) { return Collections.emptySet(); }
if (att == null)
{
att = sysprop;
@ -79,15 +80,17 @@ public class PluggableWebAppRegistrationCustomizerImpl implements WebappRegistra
}
/**
* @return The location of the jars that contain tld files.
* Jasper will discover them.
* @return The location of the jars that contain tld files. Jasper will
* discover them.
*/
public URL[] getJarsWithTlds(OSGiAppProvider provider, BundleFileLocatorHelper locatorHelper) throws Exception
{
List<URL> urls = new ArrayList<URL>();
// naive way of finding those bundles.
//lots of assumptions: for example we assume a single version of each bundle that would contain tld files.
//this is probably good enough as those tlds are loaded system-wide on jetty.
// lots of assumptions: for example we assume a single version of each
// bundle that would contain tld files.
// this is probably good enough as those tlds are loaded system-wide on
// jetty.
// to do better than this we need to do it on a per webapp basis.
// probably using custom properties in the ContextHandler service
// and mirroring those in the MANIFEST.MF
@ -108,18 +111,23 @@ public class PluggableWebAppRegistrationCustomizerImpl implements WebappRegistra
/**
* Resolves the bundle that contains tld files as a set of URLs that will be
* passed to jasper as a URLClassLoader later on.
* Usually that would be a single URL per bundle.
* But we do some more work if there are jars embedded in the bundle.
* passed to jasper as a URLClassLoader later on. Usually that would be a
* single URL per bundle. But we do some more work if there are jars
* embedded in the bundle.
*
* The jasper TldScanner expects a URLClassloader to parse a jar for the /META-INF/*.tld it may contain. We place the bundles that we know contain such
* tag-libraries. Please note that it will work if and only if the bundle is a jar (!) Currently we just hardcode the bundle that contains the jstl
* implemenation.
* The jasper TldScanner expects a URLClassloader to parse a jar for the
* /META-INF/*.tld it may contain. We place the bundles that we know contain
* such tag-libraries. Please note that it will work if and only if the
* bundle is a jar (!) Currently we just hardcode the bundle that contains
* the jstl implemenation.
*
* A workaround when the tld cannot be parsed with this method is to copy and paste it inside the WEB-INF of the webapplication where it is used.
* A workaround when the tld cannot be parsed with this method is to copy
* and paste it inside the WEB-INF of the webapplication where it is used.
*
* Support only 2 types of packaging for the bundle: - the bundle is a jar (recommended for runtime.) - the bundle is a folder and contain jars in the root
* and/or in the lib folder (nice for PDE developement situations) Unsupported: the bundle is a jar that embeds more jars.
* Support only 2 types of packaging for the bundle: - the bundle is a jar
* (recommended for runtime.) - the bundle is a folder and contain jars in
* the root and/or in the lib folder (nice for PDE developement situations)
* Unsupported: the bundle is a jar that embeds more jars.
*
* @param locatorHelper
* @param bundle

View File

@ -36,36 +36,40 @@ import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
* Fix various shortcomings with the way jasper parses the tld files.
* Plugs the JSTL tlds assuming that they are packaged with the bundle that contains the JSTL classes.
* Fix various shortcomings with the way jasper parses the tld files. Plugs the
* JSTL tlds assuming that they are packaged with the bundle that contains the
* JSTL classes.
* <p>
* Pluggable tlds at the server level are handled by {@link PluggableWebAppRegistrationCustomizerImpl}.
* Pluggable tlds at the server level are handled by
* {@link PluggableWebAppRegistrationCustomizerImpl}.
* </p>
*/
public class WebappRegistrationCustomizerImpl implements WebappRegistrationCustomizer
{
/**
* Default name of a class that belongs to the jstl bundle.
* From that class we locate the corresponding bundle and register it
* as a bundle that contains tld files.
* Default name of a class that belongs to the jstl bundle. From that class
* we locate the corresponding bundle and register it as a bundle that
* contains tld files.
*/
private static String DEFAULT_JSTL_BUNDLE_CLASS = "org.apache.taglibs.standard.tag.el.core.WhenTag";
// used to be "org.apache.jasper.runtime.JspFactoryImpl" but now
// the standard tag library implementation are stored in a separate bundle.
// DISABLED please use the tld bundle argument for the OSGiAppProvider
// /**
// * Default name of a class that belongs to the bundle where the Java server Faces tld files are defined.
// * Default name of a class that belongs to the bundle where the Java
// server Faces tld files are defined.
// * This is the sun's reference implementation.
// */
// private static String DEFAUT_JSF_IMPL_CLASS = "com.sun.faces.config.ConfigureListener";
// private static String DEFAUT_JSF_IMPL_CLASS =
// "com.sun.faces.config.ConfigureListener";
/**
* Default jsp factory implementation.
* Idally jasper is osgified and we can use services.
* In the mean time we statically set the jsp factory implementation.
* bug #299733
* Default jsp factory implementation. Idally jasper is osgified and we can
* use services. In the mean time we statically set the jsp factory
* implementation. bug #299733
*/
private static String DEFAULT_JSP_FACTORY_IMPL_CLASS = "org.apache.jasper.runtime.JspFactoryImpl";
@ -91,11 +95,11 @@ public class WebappRegistrationCustomizerImpl implements WebappRegistrationCusto
JspFactory fact = JspFactory.getDefaultFactory();
if (fact == null)
{ // bug #299733
//JspFactory does a simple Class.getForName("org.apache.jasper.runtime.JspFactoryImpl")
// JspFactory does a simple
// Class.getForName("org.apache.jasper.runtime.JspFactoryImpl")
// however its bundles does not import the jasper package
// so it fails. let's help things out:
fact = (JspFactory)JettyBootstrapActivator.class.getClassLoader()
.loadClass(DEFAULT_JSP_FACTORY_IMPL_CLASS).newInstance();
fact = (JspFactory) JettyBootstrapActivator.class.getClassLoader().loadClass(DEFAULT_JSP_FACTORY_IMPL_CLASS).newInstance();
JspFactory.setDefaultFactory(fact);
}
@ -108,20 +112,26 @@ public class WebappRegistrationCustomizerImpl implements WebappRegistrationCusto
}
/**
* The jasper TldScanner expects a URLClassloader to parse a jar for the /META-INF/*.tld it may contain. We place the bundles that we know contain such
* tag-libraries. Please note that it will work if and only if the bundle is a jar (!) Currently we just hardcode the bundle that contains the jstl
* implemenation.
* The jasper TldScanner expects a URLClassloader to parse a jar for the
* /META-INF/*.tld it may contain. We place the bundles that we know contain
* such tag-libraries. Please note that it will work if and only if the
* bundle is a jar (!) Currently we just hardcode the bundle that contains
* the jstl implemenation.
*
* A workaround when the tld cannot be parsed with this method is to copy and paste it inside the WEB-INF of the webapplication where it is used.
* A workaround when the tld cannot be parsed with this method is to copy
* and paste it inside the WEB-INF of the webapplication where it is used.
*
* Support only 2 types of packaging for the bundle: - the bundle is a jar (recommended for runtime.) - the bundle is a folder and contain jars in the root
* and/or in the lib folder (nice for PDE developement situations) Unsupported: the bundle is a jar that embeds more jars.
* Support only 2 types of packaging for the bundle: - the bundle is a jar
* (recommended for runtime.) - the bundle is a folder and contain jars in
* the root and/or in the lib folder (nice for PDE developement situations)
* Unsupported: the bundle is a jar that embeds more jars.
*
* @return array of URLs
* @throws Exception
*/
public URL[] getJarsWithTlds(OSGiAppProvider provider, BundleFileLocatorHelper locatorHelper) throws Exception
{
HashSet<Class<?>> classesToAddToTheTldBundles = new HashSet<Class<?>>();
// Look for the jstl bundle
@ -167,20 +177,20 @@ public class WebappRegistrationCustomizerImpl implements WebappRegistrationCusto
return urls.toArray(new URL[urls.size()]);
}
/**
* Jasper resolves the dtd when it parses a taglib descriptor.
* It uses this code to do that: ParserUtils.getClass().getResourceAsStream(resourcePath); where
* resourcePath is for example: /javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd Unfortunately,
* the dtd file is not in the exact same classloader as
* ParserUtils class and the dtds are packaged in 2 separate bundles.
* OSGi does not look in the dependencies' classloader when a resource is searched.
* Jasper resolves the dtd when it parses a taglib descriptor. It uses this
* code to do that:
* ParserUtils.getClass().getResourceAsStream(resourcePath); where
* resourcePath is for example:
* /javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd Unfortunately, the
* dtd file is not in the exact same classloader as ParserUtils class and
* the dtds are packaged in 2 separate bundles. OSGi does not look in the
* dependencies' classloader when a resource is searched.
* <p>
* The workaround consists of setting the entity resolver. That is a patch
* added to the version of glassfish-jasper-jetty. IT is also present in the latest
* version of glassfish jasper. Could not use introspection to set new value
* on a static friendly field :(
* added to the version of glassfish-jasper-jetty. IT is also present in the
* latest version of glassfish jasper. Could not use introspection to set
* new value on a static friendly field :(
* </p>
*/
void fixupDtdResolution()
@ -198,29 +208,23 @@ public class WebappRegistrationCustomizerImpl implements WebappRegistrationCusto
}
/**
* Instead of using the ParserUtil's classloader, we use a class that is indeed next to the resource for sure.
* Instead of using the ParserUtil's classloader, we use a class that is
* indeed next to the resource for sure.
*/
static class MyFixedupEntityResolver implements EntityResolver
{
/**
* Same values than in ParserUtils...
*/
static final String[] CACHED_DTD_PUBLIC_IDS =
{ Constants.TAGLIB_DTD_PUBLIC_ID_11, Constants.TAGLIB_DTD_PUBLIC_ID_12,
static final String[] CACHED_DTD_PUBLIC_IDS = { Constants.TAGLIB_DTD_PUBLIC_ID_11, Constants.TAGLIB_DTD_PUBLIC_ID_12,
Constants.WEBAPP_DTD_PUBLIC_ID_22, Constants.WEBAPP_DTD_PUBLIC_ID_23, };
static final String[] CACHED_DTD_RESOURCE_PATHS =
{ Constants.TAGLIB_DTD_RESOURCE_PATH_11,
Constants.TAGLIB_DTD_RESOURCE_PATH_12,
Constants.WEBAPP_DTD_RESOURCE_PATH_22,
Constants.WEBAPP_DTD_RESOURCE_PATH_23, };
static final String[] CACHED_DTD_RESOURCE_PATHS = { Constants.TAGLIB_DTD_RESOURCE_PATH_11, Constants.TAGLIB_DTD_RESOURCE_PATH_12,
Constants.WEBAPP_DTD_RESOURCE_PATH_22, Constants.WEBAPP_DTD_RESOURCE_PATH_23, };
static final String[] CACHED_SCHEMA_RESOURCE_PATHS = { Constants.TAGLIB_SCHEMA_RESOURCE_PATH_20, Constants.TAGLIB_SCHEMA_RESOURCE_PATH_21,
Constants.WEBAPP_SCHEMA_RESOURCE_PATH_24, Constants.WEBAPP_SCHEMA_RESOURCE_PATH_25, };
static final String[] CACHED_SCHEMA_RESOURCE_PATHS = {
Constants.TAGLIB_SCHEMA_RESOURCE_PATH_20,
Constants.TAGLIB_SCHEMA_RESOURCE_PATH_21,
Constants.WEBAPP_SCHEMA_RESOURCE_PATH_24,
Constants.WEBAPP_SCHEMA_RESOURCE_PATH_25,
};
public InputSource resolveEntity(String publicId, String systemId) throws SAXException
{
for (int i = 0; i < CACHED_DTD_PUBLIC_IDS.length; i++)
@ -241,10 +245,7 @@ public class WebappRegistrationCustomizerImpl implements WebappRegistrationCusto
input = this.getClass().getResourceAsStream(resourcePath);
}
}
if (input == null)
{
throw new SAXException(Localizer.getMessage("jsp.error.internal.filenotfound",resourcePath));
}
if (input == null) { throw new SAXException(Localizer.getMessage("jsp.error.internal.filenotfound", resourcePath)); }
InputSource isrc = new InputSource(input);
return isrc;
}

View File

@ -19,15 +19,14 @@ import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
/**
* Pseudo fragment activator.
* Called by the main org.eclipse.jetty.osgi.boot bundle.
* Please note: this is not a real BundleActivator. Simply something called back by
* the host bundle.
* Pseudo fragment activator. Called by the main org.eclipse.jetty.osgi.boot
* bundle. Please note: this is not a real BundleActivator. Simply something
* called back by the host bundle.
* <p>
* It must be placed in the org.eclipse.jetty.osgi.boot.jsp package:
* this is because org.eclipse.jetty.osgi.boot.jsp is the sympbolic-name
* of this fragment. From that name, the PackageadminTracker will call
* this class. IN a different package it won't be called.
* It must be placed in the org.eclipse.jetty.osgi.boot.jsp package: this is
* because org.eclipse.jetty.osgi.boot.jsp is the sympbolic-name of this
* fragment. From that name, the PackageadminTracker will call this class. IN a
* different package it won't be called.
* </p>
*/
public class FragmentActivator implements BundleActivator
@ -35,7 +34,8 @@ public class FragmentActivator implements BundleActivator
/**
*
*/
public void start(BundleContext context) throws Exception {
public void start(BundleContext context) throws Exception
{
System.setProperty("org.apache.jasper.compiler.disablejsr199", Boolean.TRUE.toString());
WebBundleDeployerHelper.JSP_REGISTRATION_HELPERS.add(new WebappRegistrationCustomizerImpl());
WebBundleDeployerHelper.JSP_REGISTRATION_HELPERS.add(new PluggableWebAppRegistrationCustomizerImpl());
@ -44,7 +44,8 @@ public class FragmentActivator implements BundleActivator
/**
*
*/
public void stop(BundleContext context) throws Exception {
public void stop(BundleContext context) throws Exception
{
}
}

View File

@ -35,13 +35,14 @@ import org.osgi.util.tracker.ServiceTracker;
* Replacement for {@link TagLibConfiguration} for the OSGi integration.
* </p>
* <p>
* In the case of a WAB, tlds can be located in OSGi bundles that are dependencies
* of the WAB.
* It is expected that each WAB lists the symbolic-names of the bundles that contain
* tld files. The list is defined as the value of the header 'Require-TldBundle'
* In the case of a WAB, tlds can be located in OSGi bundles that are
* dependencies of the WAB. It is expected that each WAB lists the
* symbolic-names of the bundles that contain tld files. The list is defined as
* the value of the header 'Require-TldBundle'
* </p>
* <p>
* Discussions about this are logged in https://bugs.eclipse.org/bugs/show_bug.cgi?id=306971
* Discussions about this are logged in
* https://bugs.eclipse.org/bugs/show_bug.cgi?id=306971
* </p>
*/
public class TagLibOSGiConfiguration extends TagLibConfiguration
@ -51,11 +52,11 @@ public class TagLibOSGiConfiguration extends TagLibConfiguration
private ServiceTracker packageAdminServiceTracker = null;
/**
* Override the preConfigure; locates the bundles that contain
* tld files according to the value of the manifest header Require-TldBundle.
* Override the preConfigure; locates the bundles that contain tld files
* according to the value of the manifest header Require-TldBundle.
* <p>
* Set or add to the property TldProcessor.TLDResources the list of located jars
* so that the super class will scan those.
* Set or add to the property TldProcessor.TLDResources the list of located
* jars so that the super class will scan those.
* </p>
*/
public void preConfigure(WebAppContext context) throws Exception
@ -66,8 +67,7 @@ public class TagLibOSGiConfiguration extends TagLibConfiguration
Collection<Resource> resources = getRequireTldBundleAsJettyResources(context, requireTldBundle);
if (resources != null && !resources.isEmpty())
{
Collection<Resource> previouslySet = (Collection<Resource>)
context.getAttribute(TagLibConfiguration.TLD_RESOURCES);
Collection<Resource> previouslySet = (Collection<Resource>) context.getAttribute(TagLibConfiguration.TLD_RESOURCES);
if (previouslySet != null)
{
resources.addAll(previouslySet);
@ -80,15 +80,13 @@ public class TagLibOSGiConfiguration extends TagLibConfiguration
}
/**
* @param requireTldBundle The comma separated list of bundles' symbolic names
* that contain tld for this osgi webapp.
* @param requireTldBundle The comma separated list of bundles' symbolic
* names that contain tld for this osgi webapp.
* @return The collection of jars or folders that match those bundles.
*/
private Collection<Resource> getRequireTldBundleAsJettyResources(
WebAppContext context, String requireTldBundle)
private Collection<Resource> getRequireTldBundleAsJettyResources(WebAppContext context, String requireTldBundle)
{
Bundle bundle = (Bundle)
context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE);
Bundle bundle = (Bundle) context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE);
PackageAdmin packAdmin = getBundleAdmin();
String[] symbNames = requireTldBundle.split(", ");
Collection<Resource> tlds = new LinkedHashSet<Resource>();
@ -97,8 +95,8 @@ public class TagLibOSGiConfiguration extends TagLibConfiguration
Bundle[] bs = packAdmin.getBundles(symbName, null);
if (bs == null || bs.length == 0)
{
throw new IllegalArgumentException("Unable to locate the bundle '"
+ symbName + "' specified in the "
throw new IllegalArgumentException("Unable to locate the bundle '" + symbName
+ "' specified in the "
+ OSGiWebappConstants.REQUIRE_TLD_BUNDLE
+ " of the manifest of "
+ bundle.getSymbolicName());
@ -118,10 +116,10 @@ public class TagLibOSGiConfiguration extends TagLibConfiguration
}
catch (IOException e)
{
throw new IllegalArgumentException("Unable to locate the "
+ "tld resource in '"
throw new IllegalArgumentException("Unable to locate the " + "tld resource in '"
+ url.toString()
+ "' in the bundle '" + bs[0].getSymbolicName()
+ "' in the bundle '"
+ bs[0].getSymbolicName()
+ "' while registering the "
+ OSGiWebappConstants.REQUIRE_TLD_BUNDLE
+ " of the manifest of "
@ -131,8 +129,8 @@ public class TagLibOSGiConfiguration extends TagLibConfiguration
}
if (!atLeastOneTldFound)
{
LOG.warn("No '/META-INF/*.tld' resources were found "
+ " in the bundle '" + bs[0].getSymbolicName()
LOG.warn("No '/META-INF/*.tld' resources were found " + " in the bundle '"
+ bs[0].getSymbolicName()
+ "' while registering the "
+ OSGiWebappConstants.REQUIRE_TLD_BUNDLE
+ " of the manifest of "
@ -147,8 +145,7 @@ public class TagLibOSGiConfiguration extends TagLibConfiguration
if (packageAdminServiceTracker == null)
{
Bundle bootBundle = ((BundleReference) OSGiWebappConstants.class.getClassLoader()).getBundle();
packageAdminServiceTracker = new ServiceTracker(bootBundle.getBundleContext(),
PackageAdmin.class.getName(), null);
packageAdminServiceTracker = new ServiceTracker(bootBundle.getBundleContext(), PackageAdmin.class.getName(), null);
packageAdminServiceTracker.open();
}
return (PackageAdmin) packageAdminServiceTracker.getService();

View File

@ -24,12 +24,13 @@ import java.util.jar.Manifest;
import org.eclipse.jetty.osgi.boot.warurl.internal.WarBundleManifestGenerator;
import org.eclipse.jetty.osgi.boot.warurl.internal.WarURLConnection;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.resource.Resource;
import org.osgi.service.url.AbstractURLStreamHandlerService;
/**
* RFC-66: support for the "war" protocol
* We are reusing the parsing of the query string from jetty.
* If we wanted to not depend on jetty at all we could duplicate that method here
* RFC-66: support for the "war" protocol We are reusing the parsing of the
* query string from jetty. If we wanted to not depend on jetty at all we could
* duplicate that method here
*/
public class WarUrlStreamHandler extends AbstractURLStreamHandlerService
{
@ -59,8 +60,10 @@ public class WarUrlStreamHandler extends AbstractURLStreamHandlerService
// if (actual.toString().startsWith("file:/") && ! actual.to)
URLConnection ori = (URLConnection) actual.openConnection();
ori.setDefaultUseCaches(Resource.getDefaultUseCaches());
JarURLConnection jarOri = null;
try {
try
{
if (ori instanceof JarURLConnection)
{
jarOri = (JarURLConnection) ori;
@ -68,18 +71,30 @@ public class WarUrlStreamHandler extends AbstractURLStreamHandlerService
else
{
jarOri = (JarURLConnection) new URL("jar:" + actual.toString() + "!/").openConnection();
jarOri.setDefaultUseCaches(Resource.getDefaultUseCaches());
}
Manifest mf = WarBundleManifestGenerator.createBundleManifest(jarOri.getManifest(), url, jarOri.getJarFile());
try
{
jarOri.getJarFile().close();
jarOri = null;
}
catch (Throwable t)
{
}
Manifest mf = WarBundleManifestGenerator.createBundleManifest(
jarOri.getManifest(), url, jarOri.getJarFile());
try { jarOri.getJarFile().close(); jarOri = null; } catch (Throwable t) {}
return new WarURLConnection(actual, mf);
}
finally
{
if (jarOri != null) try { jarOri.getJarFile().close(); } catch (Throwable t) {}
if (jarOri != null) try
{
jarOri.getJarFile().close();
}
catch (Throwable t)
{
}
}
}
}

View File

@ -31,6 +31,7 @@ import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.resource.Resource;
/**
* Facade for a URLConnection that will read a jar and substitute its
@ -106,6 +107,7 @@ public class WarURLConnection extends URLConnection
{
super(url);
_conn = url.openConnection();
_conn.setDefaultUseCaches(Resource.getDefaultUseCaches());
_mf = mf;
}
@Override

View File

@ -66,16 +66,20 @@ public class JettyBootstrapActivator implements BundleActivator
}
private ServiceRegistration _registeredServer;
private Server _server;
private JettyContextHandlerServiceTracker _jettyContextHandlerTracker;
private PackageAdminServiceTracker _packageAdminServiceTracker;
private BundleTracker _webBundleTracker;
private BundleContext _bundleContext;
// private ServiceRegistration _jettyServerFactoryService;
private JettyServerServiceTracker _jettyServerServiceTracker;
/**
* Setup a new jetty Server, registers it as a service. Setup the Service
* tracker for the jetty ContextHandlers that are in charge of deploying the
@ -98,9 +102,11 @@ public class JettyBootstrapActivator implements BundleActivator
// Register the Jetty Server Factory as a ManagedServiceFactory:
// Properties jettyServerMgdFactoryServiceProps = new Properties();
// jettyServerMgdFactoryServiceProps.put("pid", OSGiWebappConstants.MANAGED_JETTY_SERVER_FACTORY_PID);
// jettyServerMgdFactoryServiceProps.put("pid",
// OSGiWebappConstants.MANAGED_JETTY_SERVER_FACTORY_PID);
// _jettyServerFactoryService = context.registerService(
// ManagedServiceFactory.class.getName(), new JettyServersManagedFactory(),
// ManagedServiceFactory.class.getName(), new
// JettyServersManagedFactory(),
// jettyServerMgdFactoryServiceProps);
_jettyContextHandlerTracker = new JettyContextHandlerServiceTracker(_jettyServerServiceTracker);
@ -113,8 +119,7 @@ public class JettyBootstrapActivator implements BundleActivator
DefaultJettyAtJettyHomeHelper.startJettyAtJettyHome(context);
// now ready to support the Extender pattern:
_webBundleTracker = new BundleTracker(context,
Bundle.ACTIVE | Bundle.STOPPING, new WebBundleTrackerCustomizer());
_webBundleTracker = new BundleTracker(context, Bundle.ACTIVE | Bundle.STOPPING, new WebBundleTrackerCustomizer());
_webBundleTracker.open();
}
@ -200,13 +205,10 @@ public class JettyBootstrapActivator implements BundleActivator
* registers it as an OSGi service. The tracker
* {@link JettyContextHandlerServiceTracker} will do the actual deployment.
*
* @param contributor
* The bundle
* @param webappFolderPath
* The path to the root of the webapp. Must be a path relative to
* bundle; either an absolute path.
* @param contextPath
* The context path. Must start with "/"
* @param contributor The bundle
* @param webappFolderPath The path to the root of the webapp. Must be a
* path relative to bundle; either an absolute path.
* @param contextPath The context path. Must start with "/"
* @throws Exception
*/
public static void registerWebapplication(Bundle contributor, String webappFolderPath, String contextPath) throws Exception
@ -217,7 +219,8 @@ public class JettyBootstrapActivator implements BundleActivator
dic.put(OSGiWebappConstants.SERVICE_PROP_WAR, webappFolderPath);
dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH, contextPath);
String requireTldBundle = (String) contributor.getHeaders().get(OSGiWebappConstants.REQUIRE_TLD_BUNDLE);
if (requireTldBundle != null) {
if (requireTldBundle != null)
{
dic.put(OSGiWebappConstants.SERVICE_PROP_REQUIRE_TLD_BUNDLE, requireTldBundle);
}
contributor.getBundleContext().registerService(ContextHandler.class.getName(), contextHandler, dic);
@ -228,15 +231,11 @@ public class JettyBootstrapActivator implements BundleActivator
* registers it as an OSGi service. The tracker
* {@link JettyContextHandlerServiceTracker} will do the actual deployment.
*
* @param contributor
* The bundle
* @param webappFolderPath
* The path to the root of the webapp. Must be a path relative to
* bundle; either an absolute path.
* @param contextPath
* The context path. Must start with "/"
* @param dic
* TODO: parameter description
* @param contributor The bundle
* @param webappFolderPath The path to the root of the webapp. Must be a
* path relative to bundle; either an absolute path.
* @param contextPath The context path. Must start with "/"
* @param dic TODO: parameter description
* @throws Exception
*/
public static void registerWebapplication(Bundle contributor, String webappFolderPath, String contextPath, Dictionary<String, String> dic) throws Exception
@ -253,11 +252,9 @@ public class JettyBootstrapActivator implements BundleActivator
* registers it as an OSGi service. The tracker
* {@link JettyContextHandlerServiceTracker} will do the actual deployment.
*
* @param contributor
* The bundle that registers a new context
* @param contextFilePath
* The path to the file inside the bundle that defines the
* context.
* @param contributor The bundle that registers a new context
* @param contextFilePath The path to the file inside the bundle that
* defines the context.
* @throws Exception
*/
public static void registerContext(Bundle contributor, String contextFilePath) throws Exception
@ -270,13 +267,10 @@ public class JettyBootstrapActivator implements BundleActivator
* registers it as an OSGi service. The tracker
* {@link JettyContextHandlerServiceTracker} will do the actual deployment.
*
* @param contributor
* The bundle that registers a new context
* @param contextFilePath
* The path to the file inside the bundle that defines the
* context.
* @param dic
* TODO: parameter description
* @param contributor The bundle that registers a new context
* @param contextFilePath The path to the file inside the bundle that
* defines the context.
* @param dic TODO: parameter description
* @throws Exception
*/
public static void registerContext(Bundle contributor, String contextFilePath, Dictionary<String, String> dic) throws Exception
@ -295,8 +289,8 @@ public class JettyBootstrapActivator implements BundleActivator
/**
* Since org.eclipse.jetty.osgi.boot does not have a lazy activation policy
* when one fo the static methods to register a webapp is called we should make sure that
* the bundle is started.
* when one fo the static methods to register a webapp is called we should
* make sure that the bundle is started.
*/
private static void checkBundleActivated()
{
@ -323,5 +317,4 @@ public class JettyBootstrapActivator implements BundleActivator
return INSTANCE._bundleContext;
}
}

View File

@ -348,7 +348,7 @@ public class OSGiAppProvider extends ScanningAppProvider implements AppProvider
}
catch (IOException e)
{
e.printStackTrace();
LOG.warn(e);
return null;
}
}
@ -369,7 +369,7 @@ public class OSGiAppProvider extends ScanningAppProvider implements AppProvider
}
catch (IOException e)
{
e.printStackTrace();
LOG.warn(e);
return null;
}
}

View File

@ -175,10 +175,13 @@ public class DefaultJettyAtJettyHomeHelper {
String next = tokenizer.nextToken().trim();
if (!next.startsWith("/") && next.indexOf(':') == -1)
{
try {
try
{
next = new File(jettyhome, next).toURI().toURL().toString();
} catch (MalformedURLException e) {
e.printStackTrace();
}
catch (MalformedURLException e)
{
LOG.warn(e);
continue;
}
}
@ -225,7 +228,7 @@ public class DefaultJettyAtJettyHomeHelper {
}
if (enUrls == null || !enUrls.hasMoreElements())
{
System.err.println("Unable to locate a jetty configuration file for " + etcFile);
LOG.warn("Unable to locate a jetty configuration file for " + etcFile);
}
if (enUrls != null)
{

View File

@ -24,6 +24,8 @@ import org.eclipse.jetty.osgi.boot.internal.serverfactory.DefaultJettyAtJettyHom
import org.eclipse.jetty.osgi.boot.internal.serverfactory.IManagedJettyServerRegistry;
import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.Scanner;
import org.eclipse.jetty.webapp.WebAppContext;
import org.osgi.framework.Bundle;
@ -52,6 +54,7 @@ import org.osgi.framework.ServiceReference;
*/
public class JettyContextHandlerServiceTracker implements ServiceListener
{
private static Logger __logger = Log.getLogger(WebBundleDeployerHelper.class.getName());
/** New style: ability to manage multiple jetty instances */
private final IManagedJettyServerRegistry _registry;
@ -60,7 +63,8 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
private Map<ServiceReference, ContextHandler> _indexByServiceReference = new HashMap<ServiceReference, ContextHandler>();
/**
* The index is the bundle-symbolic-name/path/to/context/file when there is such thing
* The index is the bundle-symbolic-name/path/to/context/file when there is
* such thing
*/
private Map<String, ServiceReference> _indexByContextFile = new HashMap<String, ServiceReference>();
@ -87,17 +91,14 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
}
/**
* @param contextHome Parent folder where the context files can override the context files
* defined in the web bundles: equivalent to the contexts folder in a traditional
* jetty installation.
* when null, just do nothing.
* @param contextHome Parent folder where the context files can override the
* context files defined in the web bundles: equivalent to the
* contexts folder in a traditional jetty installation. when
* null, just do nothing.
*/
protected void setupContextHomeScanner(File contextHome) throws IOException
{
if (contextHome == null)
{
return;
}
if (contextHome == null) { return; }
final String osgiContextHomeFolderCanonicalPath = contextHome.getCanonicalPath();
_scanner = new Scanner();
_scanner.setRecursive(true);
@ -132,8 +133,7 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
/**
* Receives notification that a service has had a lifecycle change.
*
* @param ev
* The <code>ServiceEvent</code> object.
* @param ev The <code>ServiceEvent</code> object.
*/
public void serviceChanged(ServiceEvent ev)
{
@ -152,8 +152,7 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
}
catch (Exception e)
{
// TODO Auto-generated catch block
e.printStackTrace();
__logger.warn(e);
}
}
}
@ -178,8 +177,10 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
}
String contextFilePath = (String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH);
if (contextHandler instanceof WebAppContext && contextFilePath == null)
//it could be a web-application that will in fact be configured via a context file.
//that case is identified by the fact that the contextFilePath is not null
// it could be a web-application that will in fact be configured
// via a context file.
// that case is identified by the fact that the contextFilePath
// is not null
// in that case we must use the register context methods.
{
WebAppContext webapp = (WebAppContext) contextHandler;
@ -222,8 +223,9 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
}
else
{
WebAppContext handler = deployerHelper
.registerWebapplication(contributor,war,contextPath,
WebAppContext handler = deployerHelper.registerWebapplication(contributor,
war,
contextPath,
(String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_EXTRA_CLASSPATH),
(String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_BUNDLE_INSTALL_LOCATION_OVERRIDE),
(String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_REQUIRE_TLD_BUNDLE),
@ -236,16 +238,13 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
}
catch (Throwable e)
{
e.printStackTrace();
__logger.warn(e);
}
}
else
{
// consider this just an empty skeleton:
if (contextFilePath == null)
{
throw new IllegalArgumentException("the property contextFilePath is required");
}
if (contextFilePath == null) { throw new IllegalArgumentException("the property contextFilePath is required"); }
try
{
IWebBundleDeployerHelper deployerHelper = getWebBundleDeployerHelp(sr);
@ -255,12 +254,12 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
}
else
{
if (Boolean.TRUE.toString().equals(sr.getProperty(
IWebBundleDeployerHelper.INTERNAL_SERVICE_PROP_UNKNOWN_CONTEXT_HANDLER_TYPE)))
if (Boolean.TRUE.toString().equals(sr.getProperty(IWebBundleDeployerHelper.INTERNAL_SERVICE_PROP_UNKNOWN_CONTEXT_HANDLER_TYPE)))
{
contextHandler = null;
}
ContextHandler handler = deployerHelper.registerContext(contributor,contextFilePath,
ContextHandler handler = deployerHelper.registerContext(contributor,
contextFilePath,
(String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_EXTRA_CLASSPATH),
(String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_BUNDLE_INSTALL_LOCATION_OVERRIDE),
(String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_REQUIRE_TLD_BUNDLE),
@ -273,8 +272,7 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
}
catch (Throwable e)
{
// TODO Auto-generated catch block
e.printStackTrace();
__logger.warn(e);
}
}
}
@ -321,10 +319,7 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
private String getSymbolicNameAndContextFileKey(ServiceReference sr)
{
String contextFilePath = (String) sr.getProperty(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH);
if (contextFilePath != null)
{
return sr.getBundle().getSymbolicName() + "/" + contextFilePath;
}
if (contextFilePath != null) { return sr.getBundle().getSymbolicName() + "/" + contextFilePath; }
return null;
}
@ -336,10 +331,7 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
public void reloadJettyContextHandler(String canonicalNameOfFileChanged, String osgiContextHomeFolderCanonicalPath)
{
String key = getNormalizedRelativePath(canonicalNameOfFileChanged, osgiContextHomeFolderCanonicalPath);
if (key == null)
{
return;
}
if (key == null) { return; }
ServiceReference sr = _indexByContextFile.get(key);
if (sr == null)
{
@ -370,25 +362,20 @@ public class JettyContextHandlerServiceTracker implements ServiceListener
*/
private ServerInstanceWrapper getServerInstanceWrapper(String managedServerName)
{
if (_registry == null)
{
return null;
}
if (_registry == null) { return null; }
if (managedServerName == null)
{
managedServerName = OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME;
}
ServerInstanceWrapper wrapper = _registry.getServerInstanceWrapper(managedServerName);
//System.err.println("Returning " + managedServerName + " = " + wrapper);
// System.err.println("Returning " + managedServerName + " = " +
// wrapper);
return wrapper;
}
private IWebBundleDeployerHelper getWebBundleDeployerHelp(ServiceReference sr)
{
if (_registry == null)
{
return null;
}
if (_registry == null) { return null; }
String managedServerName = (String) sr.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
ServerInstanceWrapper wrapper = getServerInstanceWrapper(managedServerName);
return wrapper != null ? wrapper.getWebBundleDeployerHelp() : null;

View File

@ -247,7 +247,7 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe
catch (IOException e)
{
// nevermind. just trying our best
e.printStackTrace();
__logger.ignore(e);
}
return true;
}
@ -279,7 +279,7 @@ public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleRe
catch (Throwable t)
{
// humf that will hurt if it does not work.
t.printStackTrace();
__logger.warn("Unable to set webappcontext", t);
}
}
}

View File

@ -85,6 +85,7 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
* implementation should set a different implementation.
*/
public static BundleClassLoaderHelper BUNDLE_CLASS_LOADER_HELPER = null;
/**
* By default set to: {@link DefaultBundleClassLoaderHelper}. It supports
* equinox and apache-felix fragment bundles that are specific to an OSGi
@ -97,8 +98,9 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
* equinox and apache-felix fragment bundles that are specific to an OSGi
* implementation should set a different implementation.
* <p>
* Several of those objects can be added here: For example we could have an optional fragment that setups
* a specific implementation of JSF for the whole of jetty-osgi.
* Several of those objects can be added here: For example we could have an
* optional fragment that setups a specific implementation of JSF for the
* whole of jetty-osgi.
* </p>
*/
public static Collection<WebappRegistrationCustomizer> JSP_REGISTRATION_HELPERS = new ArrayList<WebappRegistrationCustomizer>();
@ -150,28 +152,22 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
/**
* Deploy a new web application on the jetty server.
*
* @param bundle
* The bundle
* @param webappFolderPath
* The path to the root of the webapp. Must be a path relative to
* bundle; either an absolute path.
* @param contextPath
* The context path. Must start with "/"
* @param bundle The bundle
* @param webappFolderPath The path to the root of the webapp. Must be a
* path relative to bundle; either an absolute path.
* @param contextPath The context path. Must start with "/"
* @param extraClasspath
* @param overrideBundleInstallLocation
* @param requireTldBundle The list of bundles's symbolic names that contain
* tld files that are required by this WAB.
* @param webXmlPath
* @param defaultWebXmlPath
* TODO: parameter description
* @param defaultWebXmlPath TODO: parameter description
* @return The contexthandler created and started
* @throws Exception
*/
public WebAppContext registerWebapplication(Bundle bundle,
String webappFolderPath, String contextPath, String extraClasspath,
String overrideBundleInstallLocation,
String requireTldBundle, String webXmlPath,
String defaultWebXmlPath, WebAppContext webAppContext) throws Exception
public WebAppContext registerWebapplication(Bundle bundle, String webappFolderPath, String contextPath, String extraClasspath,
String overrideBundleInstallLocation, String requireTldBundle, String webXmlPath, String defaultWebXmlPath,
WebAppContext webAppContext) throws Exception
{
File bundleInstall = overrideBundleInstallLocation == null ? BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(bundle) : new File(
overrideBundleInstallLocation);
@ -201,26 +197,31 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
{
webapp = bundleInstall;
}
if (baseWebappInstallURL == null && (webapp == null || !webapp.exists()))
{
throw new IllegalArgumentException("Unable to locate " + webappFolderPath + " inside "
+ (bundleInstall != null?bundleInstall.getAbsolutePath():"unlocated bundle '" + bundle.getSymbolicName() + "'"));
}
if (baseWebappInstallURL == null && (webapp == null || !webapp.exists())) { throw new IllegalArgumentException(
"Unable to locate " + webappFolderPath
+ " inside "
+ (bundleInstall != null ? bundleInstall.getAbsolutePath() : "unlocated bundle '" + bundle.getSymbolicName()
+ "'")); }
if (baseWebappInstallURL == null && webapp != null)
{
baseWebappInstallURL = webapp.toURI().toURL();
}
return registerWebapplication(bundle,webappFolderPath,baseWebappInstallURL,contextPath,
extraClasspath,bundleInstall,requireTldBundle,webXmlPath,defaultWebXmlPath,webAppContext);
return registerWebapplication(bundle, webappFolderPath, baseWebappInstallURL, contextPath, extraClasspath, bundleInstall, requireTldBundle, webXmlPath,
defaultWebXmlPath, webAppContext);
}
/* (non-Javadoc)
* @see org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper#registerWebapplication(org.osgi.framework.Bundle, java.lang.String, java.io.File, java.lang.String, java.lang.String, java.io.File, java.lang.String, java.lang.String)
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper#
* registerWebapplication(org.osgi.framework.Bundle, java.lang.String,
* java.io.File, java.lang.String, java.lang.String, java.io.File,
* java.lang.String, java.lang.String)
*/
private WebAppContext registerWebapplication(Bundle contributor, String pathInBundleToWebApp,
URL baseWebappInstallURL, String contextPath, String extraClasspath, File bundleInstall,
String requireTldBundle, String webXmlPath, String defaultWebXmlPath, WebAppContext context)
throws Exception
private WebAppContext registerWebapplication(Bundle contributor, String pathInBundleToWebApp, URL baseWebappInstallURL, String contextPath,
String extraClasspath, File bundleInstall, String requireTldBundle, String webXmlPath,
String defaultWebXmlPath, WebAppContext context) throws Exception
{
ClassLoader contextCl = Thread.currentThread().getContextClassLoader();
@ -228,10 +229,16 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
try
{
//apply any META-INF/context.xml file that is found to configure the webapp first
applyMetaInfContextXml (contributor, context);
// make sure we provide access to all the jetty bundles by going
// through this bundle.
OSGiWebappClassLoader composite = createWebappClassLoader(contributor);
// configure with access to all jetty classes and also all the classes
// configure with access to all jetty classes and also all the
// classes
// that the contributor gives access to.
Thread.currentThread().setContextClassLoader(composite);
@ -284,7 +291,6 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
configureWebappClassLoader(contributor, context, composite, requireTldBundle);
configureWebAppContext(context, contributor, requireTldBundle);
// @see
// org.eclipse.jetty.webapp.JettyWebXmlConfiguration#configure(WebAppContext)
// during initialization of the webapp all the jetty packages are
@ -295,13 +301,14 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
_wrapper.getOSGiAppProvider().addContext(contributor, pathInBundleToWebApp, context);
//support for patch resources. ideally this should be done inside a configurator.
List<Resource> patchResources =
(List<Resource>)context.getAttribute(WebInfConfiguration.RESOURCE_URLS+".patch");
// support for patch resources. ideally this should be done inside a
// configurator.
List<Resource> patchResources = (List<Resource>) context.getAttribute(WebInfConfiguration.RESOURCE_URLS + ".patch");
if (patchResources != null)
{
LinkedList<Resource> resourcesPath = new LinkedList<Resource>();
//place the patch resources at the beginning of the lookup path.
// place the patch resources at the beginning of the lookup
// path.
resourcesPath.addAll(patchResources);
// then place the ones from the host web bundle.
Resource hostResources = context.getBaseResource();
@ -317,8 +324,7 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
resourcesPath.add(hostResources);
}
ResourceCollection rc = new ResourceCollection(resourcesPath.toArray(
new Resource[resourcesPath.size()]));
ResourceCollection rc = new ResourceCollection(resourcesPath.toArray(new Resource[resourcesPath.size()]));
context.setBaseResource(rc);
}
@ -335,34 +341,37 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
}
/* (non-Javadoc)
* @see org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper#unregister(org.eclipse.jetty.server.handler.ContextHandler)
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper#
* unregister(org.eclipse.jetty.server.handler.ContextHandler)
*/
public void unregister(ContextHandler contextHandler) throws Exception
{
_wrapper.getOSGiAppProvider().removeContext(contextHandler);
}
/* (non-Javadoc)
* @see org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper#registerContext(org.osgi.framework.Bundle, java.lang.String, java.lang.String, java.lang.String)
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper#
* registerContext(org.osgi.framework.Bundle, java.lang.String,
* java.lang.String, java.lang.String)
*/
public ContextHandler registerContext(Bundle contributor, String contextFileRelativePath, String extraClasspath,
String overrideBundleInstallLocation, String requireTldBundle, ContextHandler handler)
throws Exception
public ContextHandler registerContext(Bundle contributor, String contextFileRelativePath, String extraClasspath, String overrideBundleInstallLocation,
String requireTldBundle, ContextHandler handler) throws Exception
{
File contextsHome = _wrapper.getOSGiAppProvider().getContextXmlDirAsFile();
if (contextsHome != null)
{
File prodContextFile = new File(contextsHome, contributor.getSymbolicName() + "/" + contextFileRelativePath);
if (prodContextFile.exists())
{
return registerContext(contributor,contextFileRelativePath,prodContextFile,extraClasspath,
overrideBundleInstallLocation,requireTldBundle,handler);
if (prodContextFile.exists()) { return registerContext(contributor, contextFileRelativePath, prodContextFile, extraClasspath,
overrideBundleInstallLocation, requireTldBundle, handler); }
}
}
File rootFolder = overrideBundleInstallLocation != null
? Resource.newResource(overrideBundleInstallLocation).getFile()
: BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(contributor);
File rootFolder = overrideBundleInstallLocation != null ? Resource.newResource(overrideBundleInstallLocation).getFile() : BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(contributor);
File contextFile = rootFolder != null ? new File(rootFolder, contextFileRelativePath) : null;
if (contextFile != null && contextFile.exists())
{
@ -383,10 +392,14 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
if (contextURL != null)
{
Resource r = Resource.newResource(contextURL);
return registerContext(contributor,contextFileRelativePath,r.getInputStream(),extraClasspath,overrideBundleInstallLocation,requireTldBundle,handler);
return registerContext(contributor, contextFileRelativePath, r.getInputStream(), extraClasspath, overrideBundleInstallLocation,
requireTldBundle, handler);
}
throw new IllegalArgumentException("Could not find the context " + "file " + contextFileRelativePath + " for the bundle "
+ contributor.getSymbolicName() + (overrideBundleInstallLocation != null?" using the install location " + overrideBundleInstallLocation:""));
throw new IllegalArgumentException("Could not find the context " + "file "
+ contextFileRelativePath
+ " for the bundle "
+ contributor.getSymbolicName()
+ (overrideBundleInstallLocation != null ? " using the install location " + overrideBundleInstallLocation : ""));
}
}
@ -400,16 +413,14 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
* @param classInBundle
* @throws Exception
*/
private ContextHandler registerContext(Bundle contributor, String pathInBundle, File contextFile,
String extraClasspath, String overrideBundleInstallLocation,
String requireTldBundle, ContextHandler handler) throws Exception
private ContextHandler registerContext(Bundle contributor, String pathInBundle, File contextFile, String extraClasspath,
String overrideBundleInstallLocation, String requireTldBundle, ContextHandler handler) throws Exception
{
InputStream contextFileInputStream = null;
try
{
contextFileInputStream = new BufferedInputStream(new FileInputStream(contextFile));
return registerContext(contributor, pathInBundle, contextFileInputStream,
extraClasspath,overrideBundleInstallLocation,requireTldBundle,handler);
return registerContext(contributor, pathInBundle, contextFileInputStream, extraClasspath, overrideBundleInstallLocation, requireTldBundle, handler);
}
finally
{
@ -424,11 +435,8 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
* happen.
* @throws Exception
*/
private ContextHandler registerContext(Bundle contributor,
String pathInsideBundle, InputStream contextFileInputStream,
String extraClasspath, String overrideBundleInstallLocation,
String requireTldBundle, ContextHandler handler)
throws Exception
private ContextHandler registerContext(Bundle contributor, String pathInsideBundle, InputStream contextFileInputStream, String extraClasspath,
String overrideBundleInstallLocation, String requireTldBundle, ContextHandler handler) throws Exception
{
ClassLoader contextCl = Thread.currentThread().getContextClassLoader();
String[] oldServerClasses = null;
@ -442,9 +450,8 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
// classes
// that the contributor gives access to.
Thread.currentThread().setContextClassLoader(composite);
ContextHandler context = createContextHandler(handler, contributor,
contextFileInputStream,extraClasspath,
overrideBundleInstallLocation,requireTldBundle);
ContextHandler context = createContextHandler(handler, contributor, contextFileInputStream, extraClasspath, overrideBundleInstallLocation,
requireTldBundle);
if (context == null)
{
return null;// did not happen
@ -485,8 +492,7 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
* @see {WebAppDeployer#scan} around the comment
* <code>// configure it</code>
*/
protected void configureWebAppContext(ContextHandler wah, Bundle contributor,
String requireTldBundle) throws IOException
protected void configureWebAppContext(ContextHandler wah, Bundle contributor, String requireTldBundle) throws IOException
{
// rfc66
wah.setAttribute(OSGiWebappConstants.RFC66_OSGI_BUNDLE_CONTEXT, contributor.getBundleContext());
@ -495,50 +501,49 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
// not a spec... but if we want to support
// org.springframework.osgi.web.context.support.OsgiBundleXmlWebApplicationContext
// then we need to do this to:
wah.setAttribute("org.springframework.osgi.web." + BundleContext.class.getName(),
contributor.getBundleContext());
wah.setAttribute("org.springframework.osgi.web." + BundleContext.class.getName(), contributor.getBundleContext());
//also pass the bundle directly. sometimes a bundle does not have a bundlecontext.
//it is still useful to have access to the Bundle from the servlet context.
// also pass the bundle directly. sometimes a bundle does not have a
// bundlecontext.
// it is still useful to have access to the Bundle from the servlet
// context.
wah.setAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE, contributor);
//pass the value of the require tld bundle so that the TagLibOSGiConfiguration
// pass the value of the require tld bundle so that the
// TagLibOSGiConfiguration
// can pick it up.
wah.setAttribute(OSGiWebappConstants.REQUIRE_TLD_BUNDLE, requireTldBundle);
if (wah instanceof WebAppContext)
{
if (_wrapper.getOSGiAppProvider().getConfigurationClasses() != null)
{
((WebAppContext)wah).setConfigurationClasses(_wrapper.getOSGiAppProvider().getConfigurationClasses());
}
}
Bundle[] fragments = PackageAdminServiceTracker.INSTANCE.getFragmentsAndRequiredBundles(contributor);
if (fragments != null && fragments.length != 0)
{
// sorted extra resource base found in the fragments.
//the resources are either overriding the resourcebase found in the web-bundle
// the resources are either overriding the resourcebase found in the
// web-bundle
// or appended.
//amongst each resource we sort them according to the alphabetical order
//of the name of the internal folder and the symbolic name of the fragment.
// amongst each resource we sort them according to the alphabetical
// order
// of the name of the internal folder and the symbolic name of the
// fragment.
// this is useful to make sure that the lookup path of those
// resource base defined by fragments is always the same.
//This natural order could be abused to define the order in which the base resources are
// This natural order could be abused to define the order in which
// the base resources are
// looked up.
TreeMap<String, Resource> patchResourcesPath = new TreeMap<String, Resource>();
TreeMap<String, Resource> appendedResourcesPath = new TreeMap<String, Resource>();
for (Bundle frag : fragments) {
for (Bundle frag : fragments)
{
String fragFolder = (String) frag.getHeaders().get(OSGiWebappConstants.JETTY_WAR_FRAGMENT_FOLDER_PATH);
String patchFragFolder = (String) frag.getHeaders().get(OSGiWebappConstants.JETTY_WAR_PATCH_FRAGMENT_FOLDER_PATH);
if (fragFolder != null)
{
URL fragUrl = frag.getEntry(fragFolder);
if (fragUrl == null)
{
throw new IllegalArgumentException("Unable to locate " + fragFolder + " inside "
+ " the fragment '" + frag.getSymbolicName() + "'");
}
if (fragUrl == null) { throw new IllegalArgumentException("Unable to locate " + fragFolder
+ " inside "
+ " the fragment '"
+ frag.getSymbolicName()
+ "'"); }
fragUrl = DefaultFileLocatorHelper.getLocalURL(fragUrl);
String key = fragFolder.startsWith("/") ? fragFolder.substring(1) : fragFolder;
appendedResourcesPath.put(key + ";" + frag.getSymbolicName(), Resource.newResource(fragUrl));
@ -546,11 +551,11 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
if (patchFragFolder != null)
{
URL patchFragUrl = frag.getEntry(patchFragFolder);
if (patchFragUrl == null)
{
throw new IllegalArgumentException("Unable to locate " + patchFragUrl + " inside "
+ " the fragment '" + frag.getSymbolicName() + "'");
}
if (patchFragUrl == null) { throw new IllegalArgumentException("Unable to locate " + patchFragUrl
+ " inside "
+ " the fragment '"
+ frag.getSymbolicName()
+ "'"); }
patchFragUrl = DefaultFileLocatorHelper.getLocalURL(patchFragUrl);
String key = patchFragFolder.startsWith("/") ? patchFragFolder.substring(1) : patchFragFolder;
patchResourcesPath.put(key + ";" + frag.getSymbolicName(), Resource.newResource(patchFragUrl));
@ -567,9 +572,11 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
if (wah instanceof WebAppContext)
{
//This is the equivalent of what MetaInfConfiguration does. For OSGi bundles without the JarScanner
// This is the equivalent of what MetaInfConfiguration does. For
// OSGi bundles without the JarScanner
WebAppContext webappCtxt = (WebAppContext) wah;
//take care of the web-fragments, meta-inf resources and tld resources:
// take care of the web-fragments, meta-inf resources and tld
// resources:
// similar to what MetaInfConfiguration does.
List<Resource> frags = (List<Resource>) wah.getAttribute(FragmentConfiguration.FRAGMENT_RESOURCES);
List<Resource> resfrags = (List<Resource>) wah.getAttribute(WebInfConfiguration.RESOURCE_URLS);
@ -579,14 +586,14 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
URL webFrag = frag.getEntry("/META-INF/web-fragment.xml");
Enumeration<URL> resEnum = frag.findEntries("/META-INF/resources", "*", true);
Enumeration<URL> tldEnum = frag.findEntries("/META-INF", "*.tld", false);
if (webFrag != null || (resEnum != null && resEnum.hasMoreElements())
|| (tldEnum != null && tldEnum.hasMoreElements()))
if (webFrag != null || (resEnum != null && resEnum.hasMoreElements()) || (tldEnum != null && tldEnum.hasMoreElements()))
{
try
{
File fragFile = BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(frag);
// add it to the webinf jars collection:
//no need to check that it was not there yet: it was not there yet for sure.
// no need to check that it was not there yet: it
// was not there yet for sure.
Resource fragFileAsResource = Resource.newResource(fragFile.toURI());
webappCtxt.getMetaData().addWebInfJar(fragFileAsResource);
@ -604,7 +611,8 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
URL resourcesEntry = frag.getEntry("/META-INF/resources/");
if (resourcesEntry == null)
{
//probably we found some fragments to a bundle.
// probably we found some fragments to a
// bundle.
// those are already contributed.
// so we skip this.
}
@ -615,8 +623,7 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
resfrags = new ArrayList<Resource>();
wah.setAttribute(WebInfConfiguration.RESOURCE_URLS, resfrags);
}
resfrags.add(Resource.newResource(
DefaultFileLocatorHelper.getLocalURL(resourcesEntry)));
resfrags.add(Resource.newResource(DefaultFileLocatorHelper.getLocalURL(resourcesEntry)));
}
}
if (tldEnum != null && tldEnum.hasMoreElements())
@ -629,8 +636,7 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
while (tldEnum.hasMoreElements())
{
URL tldUrl = tldEnum.nextElement();
tldfrags.add(Resource.newResource(
DefaultFileLocatorHelper.getLocalURL(tldUrl)));
tldfrags.add(Resource.newResource(DefaultFileLocatorHelper.getLocalURL(tldUrl)));
}
}
}
@ -643,7 +649,6 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
}
}
}
/**
@ -651,19 +656,17 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
* @param contextFile
* @return
*/
protected ContextHandler createContextHandler(ContextHandler handlerToConfigure,
Bundle bundle, File contextFile, String extraClasspath,
protected ContextHandler createContextHandler(ContextHandler handlerToConfigure, Bundle bundle, File contextFile, String extraClasspath,
String overrideBundleInstallLocation, String requireTldBundle)
{
try
{
return createContextHandler(handlerToConfigure,bundle,
new BufferedInputStream(new FileInputStream(contextFile)),
extraClasspath,overrideBundleInstallLocation,requireTldBundle);
return createContextHandler(handlerToConfigure, bundle, new BufferedInputStream(new FileInputStream(contextFile)), extraClasspath,
overrideBundleInstallLocation, requireTldBundle);
}
catch (FileNotFoundException e)
{
e.printStackTrace();
__logger.warn(e);
}
return null;
}
@ -674,8 +677,7 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
* @return
*/
@SuppressWarnings("unchecked")
protected ContextHandler createContextHandler(ContextHandler handlerToConfigure,
Bundle bundle, InputStream contextInputStream, String extraClasspath,
protected ContextHandler createContextHandler(ContextHandler handlerToConfigure, Bundle bundle, InputStream contextInputStream, String extraClasspath,
String overrideBundleInstallLocation, String requireTldBundle)
{
/*
@ -729,18 +731,15 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
}
catch (SAXException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
__logger.warn(e);
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
__logger.warn(e);
}
catch (Throwable e)
{
// TODO Auto-generated catch block
e.printStackTrace();
__logger.warn(e);
}
finally
{
@ -787,8 +786,7 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
webappClassLoader.setWebappContext(webappCtxt);
String pathsToRequiredBundles = getPathsToRequiredBundles(context, requireTldBundle);
if (pathsToRequiredBundles != null)
webappClassLoader.addClassPath(pathsToRequiredBundles);
if (pathsToRequiredBundles != null) webappClassLoader.addClassPath(pathsToRequiredBundles);
}
else
{
@ -804,23 +802,48 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
// we use a temporary WebAppContext object.
// if this is a real webapp we will set it on it a bit later: once we
// know.
OSGiWebappClassLoader webappClassLoader = new OSGiWebappClassLoader(
_wrapper.getParentClassLoaderForWebapps(),new WebAppContext(),contributor,BUNDLE_CLASS_LOADER_HELPER);
/* DEBUG
try {
Class c = webappClassLoader.loadClass("org.glassfish.jsp.api.ResourceInjector");
System.err.println("LOADED org.glassfish.jsp.api.ResourceInjector from "+c.getClassLoader());
}
catch (Exception e) {e.printStackTrace();}
try {
Class c = webappClassLoader.loadClass("org.apache.jasper.xmlparser.ParserUtils");
System.err.println("LOADED org.apache.jasper.xmlparser.ParserUtils from "+c.getClassLoader());
}
catch (Exception e) {e.printStackTrace();}
*/
OSGiWebappClassLoader webappClassLoader = new OSGiWebappClassLoader(_wrapper.getParentClassLoaderForWebapps(), new WebAppContext(), contributor,
BUNDLE_CLASS_LOADER_HELPER);
return webappClassLoader;
}
protected void applyMetaInfContextXml (Bundle bundle, ContextHandler contextHandler)
throws Exception
{
if (bundle == null)
return;
if (contextHandler == null)
return;
ClassLoader cl = Thread.currentThread().getContextClassLoader();
__logger.info("Context classloader = "+cl);
try
{
Thread.currentThread().setContextClassLoader(_wrapper.getParentClassLoaderForWebapps());
//find if there is a META-INF/context.xml file
URL contextXmlUrl = bundle.getEntry("/META-INF/jetty-webapp-context.xml");
if (contextXmlUrl == null)
return;
//Apply it just as the standard jetty ContextProvider would do
__logger.info("Applying "+contextXmlUrl+" to "+contextHandler);
XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXmlUrl);
HashMap properties = new HashMap();
properties.put("Server", _wrapper.getServer());
xmlConfiguration.getProperties().putAll(properties);
xmlConfiguration.configure(contextHandler);
}
finally
{
Thread.currentThread().setContextClassLoader(cl);
}
}
/**
* Set the property &quot;this.bundle.install&quot; to point to the location
* of the bundle. Useful when <SystemProperty name="this.bundle.home"/> is
@ -830,8 +853,7 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
{
try
{
File location = overrideBundleInstallLocation != null?new File(overrideBundleInstallLocation):BUNDLE_FILE_LOCATOR_HELPER
.getBundleInstallLocation(bundle);
File location = overrideBundleInstallLocation != null ? new File(overrideBundleInstallLocation) : BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(bundle);
properties.put("this.bundle.install", location.getCanonicalPath());
properties.put("this.bundle.install.url", bundle.getEntry("/").toString());
}
@ -841,11 +863,9 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
}
}
private String getPathsToRequiredBundles(ContextHandler context, String requireTldBundle) throws Exception
{
if (requireTldBundle == null)
return null;
if (requireTldBundle == null) return null;
StringBuilder paths = new StringBuilder();
Bundle bundle = (Bundle) context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE);
@ -857,19 +877,16 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
for (String symbName : symbNames)
{
Bundle[] bs = packAdmin.getBundles(symbName, null);
if (bs == null || bs.length == 0)
{
throw new IllegalArgumentException("Unable to locate the bundle '"
+ symbName + "' specified in the "
if (bs == null || bs.length == 0) { throw new IllegalArgumentException("Unable to locate the bundle '" + symbName
+ "' specified in the "
+ OSGiWebappConstants.REQUIRE_TLD_BUNDLE
+ " of the manifest of "
+ bundle.getSymbolicName());
}
+ bundle.getSymbolicName()); }
File f = fileLocatorHelper.getBundleInstallLocation(bs[0]);
if (paths.length() > 0)
paths.append(", ");
__logger.debug("getPathsToRequiredBundles: bundle path=" + bs[0].getLocation() + " uri=" + f.toURI());
paths.append(f.toURI().toURL().toString());
}
@ -885,6 +902,5 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
return (PackageAdmin) serviceTracker.getService();
}
}

View File

@ -24,7 +24,6 @@ import org.osgi.framework.BundleEvent;
import org.osgi.util.tracker.BundleTracker;
import org.osgi.util.tracker.BundleTrackerCustomizer;
/**
* Support bundles that declare the webapp directly through headers in their
* manifest.
@ -49,11 +48,10 @@ import org.osgi.util.tracker.BundleTrackerCustomizer;
*
* @author hmalphettes
*/
public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer {
public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer
{
private static final Logger LOG = Log.getLogger(WebBundleTrackerCustomizer.class);
/**
* A bundle is being added to the <code>BundleTracker</code>.
*
@ -68,8 +66,8 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer {
* @param bundle The <code>Bundle</code> being added to the
* <code>BundleTracker</code>.
* @param event The bundle event which caused this customizer method to be
* called or <code>null</code> if there is no bundle event associated
* with the call to this method.
* called or <code>null</code> if there is no bundle event
* associated with the call to this method.
* @return The object to be tracked for the specified <code>Bundle</code>
* object or <code>null</code> if the specified <code>Bundle</code>
* object should not be tracked.
@ -102,16 +100,14 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer {
*
* @param bundle The <code>Bundle</code> whose state has been modified.
* @param event The bundle event which caused this customizer method to be
* called or <code>null</code> if there is no bundle event associated
* with the call to this method.
* called or <code>null</code> if there is no bundle event
* associated with the call to this method.
* @param object The tracked object for the specified bundle.
*/
public void modifiedBundle(Bundle bundle, BundleEvent event,
Object object)
public void modifiedBundle(Bundle bundle, BundleEvent event, Object object)
{
// nothing the web-bundle was already track. something changed.
// we only reload the webapps if the bundle is stopped and restarted.
// System.err.println(bundle.getSymbolicName());
if (bundle.getState() == Bundle.STOPPING || bundle.getState() == Bundle.ACTIVE)
{
unregister(bundle);
@ -131,17 +127,15 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer {
*
* @param bundle The <code>Bundle</code> that has been removed.
* @param event The bundle event which caused this customizer method to be
* called or <code>null</code> if there is no bundle event associated
* with the call to this method.
* called or <code>null</code> if there is no bundle event
* associated with the call to this method.
* @param object The tracked object for the specified bundle.
*/
public void removedBundle(Bundle bundle, BundleEvent event,
Object object)
public void removedBundle(Bundle bundle, BundleEvent event, Object object)
{
unregister(bundle);
}
/**
* @param bundle
* @return true if this bundle in indeed a web-bundle.
@ -152,12 +146,15 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer {
String warFolderRelativePath = (String) dic.get(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH);
if (warFolderRelativePath != null)
{
String contextPath = (String)dic.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
String contextPath = getWebContextPath(bundle, dic, false);// (String)dic.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
if (contextPath == null || !contextPath.startsWith("/"))
{
LOG.warn("The manifest header '" + OSGiWebappConstants.JETTY_WAR_FOLDER_PATH +
": " + warFolderRelativePath + "' in the bundle " + bundle.getSymbolicName() +
" is not valid: there is no Web-ContextPath defined in the manifest.");
LOG.warn("The manifest header '" + OSGiWebappConstants.JETTY_WAR_FOLDER_PATH
+ ": "
+ warFolderRelativePath
+ "' in the bundle "
+ bundle.getSymbolicName()
+ " is not valid: there is no Web-ContextPath defined in the manifest.");
return false;
}
// create the corresponding service and publish it in the context of
@ -191,8 +188,7 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer {
}
catch (Throwable e)
{
// TODO Auto-generated catch block
e.printStackTrace();
LOG.warn(e);
}
}
return true;
@ -215,7 +211,7 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer {
// pointing to files and folders inside WEB-INF. We should
// filter-out
// META-INF too
String rfc66ContextPath = getWebContextPath(bundle,dic);
String rfc66ContextPath = getWebContextPath(bundle, dic, rfc66Webxml == null);
try
{
JettyBootstrapActivator.registerWebapplication(bundle, ".", rfc66ContextPath);
@ -223,8 +219,7 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer {
}
catch (Throwable e)
{
// TODO Auto-generated catch block
e.printStackTrace();
LOG.warn(e);
return true;// maybe it did not work maybe it did. safer to track this bundle.
}
}
@ -235,6 +230,7 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer {
String rfc66ContextPath = (String) dic.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
if (rfc66ContextPath == null)
{
if (!webinfWebxmlExists) { return null; }
// extract from the last token of the bundle's location:
// (really ?
// could consider processing the symbolic name as an alternative
@ -265,7 +261,4 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer {
// webapps registered in that bundle.
}
}

View File

@ -25,6 +25,7 @@ import java.util.zip.ZipFile;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.FileResource;
import org.osgi.framework.Bundle;
@ -43,9 +44,11 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
// The url nuxeo and felix return is created directly from the File so it
// should work.
private static Field BUNDLE_ENTRY_FIELD = null;
private static Field FILE_FIELD = null;
private static Field BUNDLE_FILE_FIELD_FOR_DIR_ZIP_BUNDLE_ENTRY = null;// ZipBundleFile
// inside
// DirZipBundleEntry
@ -56,8 +59,7 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
* spirit of OSGi but quite necessary to support self-contained webapps and
* other situations.
*
* @param bundle
* The bundle
* @param bundle The bundle
* @return Its installation location as a file.
* @throws Exception
*/
@ -67,11 +69,12 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
// grab the MANIFEST.MF's url
// and then do what it takes.
URL url = bundle.getEntry("/META-INF/MANIFEST.MF");
// System.err.println(url.toString() + " " + url.toURI() + " " + url.getProtocol());
if (url.getProtocol().equals("file"))
{
// some osgi frameworks do use the file protocole directly in some
// situations. Do use the FileResource to transform the URL into a File: URL#toURI is broken
// situations. Do use the FileResource to transform the URL into a
// File: URL#toURI is broken
return new FileResource(url).getFile().getParentFile().getParentFile();
}
else if (url.getProtocol().equals("bundleentry"))
@ -79,7 +82,10 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
// say hello to equinox who has its own protocol.
// we use introspection like there is no tomorrow to get access to
// the File
URLConnection con = url.openConnection();
con.setUseCaches(Resource.getDefaultUseCaches()); //work around problems where url connections cache references to jars
if (BUNDLE_ENTRY_FIELD == null)
{
BUNDLE_ENTRY_FIELD = con.getClass().getDeclaredField("bundleEntry");
@ -99,7 +105,10 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
else if (bundleEntry.getClass().getName().equals("org.eclipse.osgi.baseadaptor.bundlefile.ZipBundleEntry"))
{
url = bundle.getEntry("/");
con = url.openConnection();
con.setDefaultUseCaches(Resource.getDefaultUseCaches());
if (BUNDLE_ENTRY_FIELD == null)
{// this one will be a DirZipBundleEntry
BUNDLE_ENTRY_FIELD = con.getClass().getDeclaredField("bundleEntry");
@ -139,16 +148,21 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
else if (location.startsWith("file:"))
{
// location defined in the BundleArchive m_bundleArchive
//it is relative to relative to the BundleArchive's m_archiveRootDir
// it is relative to relative to the BundleArchive's
// m_archiveRootDir
File res = new File(location.substring("file:".length()));
if (!res.exists())
{
return null;
// Object bundleArchive = getFelixBundleArchive(bundle);
// File archiveRoot = getFelixBundleArchiveRootDir(bundleArchive);
// String currentLocation = getFelixBundleArchiveCurrentLocation(bundleArchive);
// System.err.println("Got the archive root " + archiveRoot.getAbsolutePath()
// + " current location " + currentLocation + " is directory ?");
// File archiveRoot =
// getFelixBundleArchiveRootDir(bundleArchive);
// String currentLocation =
// getFelixBundleArchiveCurrentLocation(bundleArchive);
// System.err.println("Got the archive root " +
// archiveRoot.getAbsolutePath()
// + " current location " + currentLocation +
// " is directory ?");
// res = new File(archiveRoot, currentLocation != null
// ? currentLocation : location.substring("file:".length()));
}
@ -182,15 +196,20 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
File webapp = path != null && path.length() != 0 ? new File(bundleInstall, path) : bundleInstall;
if (!webapp.exists())
{
throw new IllegalArgumentException("Unable to locate " + path + " inside " + bundle.getSymbolicName() + " ("
+ (bundleInstall != null?bundleInstall.getAbsolutePath():" no_bundle_location ") + ")");
throw new IllegalArgumentException("Unable to locate " + path
+ " inside "
+ bundle.getSymbolicName()
+ " ("
+ (bundleInstall != null ? bundleInstall.getAbsolutePath() : " no_bundle_location ")
+ ")");
}
return webapp;
}
/**
* Helper method equivalent to Bundle#getEntry(String entryPath) except that
* it searches for entries in the fragments by using the Bundle#findEntries method.
* it searches for entries in the fragments by using the Bundle#findEntries
* method.
*
* @param bundle
* @param entryPath
@ -199,14 +218,12 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
public Enumeration<URL> findEntries(Bundle bundle, String entryPath)
{
int last = entryPath.lastIndexOf('/');
String path = last != -1 && last < entryPath.length() -2
? entryPath.substring(0, last) : "/";
String path = last != -1 && last < entryPath.length() - 2 ? entryPath.substring(0, last) : "/";
if (!path.startsWith("/"))
{
path = "/" + path;
}
String pattern = last != -1 && last < entryPath.length() -2
? entryPath.substring(last+1) : entryPath;
String pattern = last != -1 && last < entryPath.length() - 2 ? entryPath.substring(last + 1) : entryPath;
Enumeration<URL> enUrls = bundle.findEntries(path, pattern, false);
return enUrls;
}
@ -257,48 +274,59 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
}
}
//introspection on equinox to invoke the getLocalURL method on BundleURLConnection
//equivalent to using the FileLocator without depending on an equinox class.
// introspection on equinox to invoke the getLocalURL method on
// BundleURLConnection
// equivalent to using the FileLocator without depending on an equinox
// class.
private static Method BUNDLE_URL_CONNECTION_getLocalURL = null;
private static Method BUNDLE_URL_CONNECTION_getFileURL = null;
/**
* Only useful for equinox: on felix we get the file:// or jar:// url already.
* Other OSGi implementations have not been tested
* Only useful for equinox: on felix we get the file:// or jar:// url
* already. Other OSGi implementations have not been tested
* <p>
* Get a URL to the bundle entry that uses a common protocol (i.e. file:
* jar: or http: etc.).
* </p>
*
* @return a URL to the bundle entry that uses a common protocol
*/
public static URL getLocalURL(URL url) {
if ("bundleresource".equals(url.getProtocol()) || "bundleentry".equals(url.getProtocol())) {
try {
public static URL getLocalURL(URL url)
{
if ("bundleresource".equals(url.getProtocol()) || "bundleentry".equals(url.getProtocol()))
{
try
{
URLConnection conn = url.openConnection();
if (BUNDLE_URL_CONNECTION_getLocalURL == null &&
conn.getClass().getName().equals(
"org.eclipse.osgi.framework.internal.core.BundleURLConnection")) {
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);
if (BUNDLE_URL_CONNECTION_getLocalURL != null) { return (URL) BUNDLE_URL_CONNECTION_getLocalURL.invoke(conn, null); }
}
} catch (Throwable t) {
catch (Throwable t)
{
System.err.println("Unable to locate the OSGi url: '" + url + "'.");
t.printStackTrace();
}
}
return url;
}
/**
* Only useful for equinox: on felix we get the file:// url already.
* Other OSGi implementations have not been tested
* Only useful for equinox: on felix we get the file:// url already. Other
* OSGi implementations have not been tested
* <p>
* Get a URL to the content of the bundle entry that uses the file: protocol.
* The content of the bundle entry may be downloaded or extracted to the local
* file system in order to create a file: URL.
* @return a URL to the content of the bundle entry that uses the file: protocol
* Get a URL to the content of the bundle entry that uses the file:
* protocol. The content of the bundle entry may be downloaded or extracted
* to the local file system in order to create a file: URL.
*
* @return a URL to the content of the bundle entry that uses the file:
* protocol
* </p>
*/
public static URL getFileURL(URL url)
@ -308,17 +336,14 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper
try
{
URLConnection conn = url.openConnection();
if (BUNDLE_URL_CONNECTION_getFileURL == null &&
conn.getClass().getName().equals(
"org.eclipse.osgi.framework.internal.core.BundleURLConnection"))
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);
}
if (BUNDLE_URL_CONNECTION_getFileURL != null) { return (URL) BUNDLE_URL_CONNECTION_getFileURL.invoke(conn, null); }
}
catch (Throwable t)
{

View File

@ -14,3 +14,4 @@ Import-Package: javax.servlet;version="2.6.0",
org.eclipse.jetty.servlet;version="8.1.3",
org.eclipse.jetty.util.component;version="8.1.3"
Export-Package: org.eclipse.jetty.osgi.httpservice;version="8.1.3"

View File

@ -1,149 +0,0 @@
package org.eclipse.jetty.rewrite.handler;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.ContextHandler.Context;
import org.eclipse.jetty.server.handler.ScopedHandler;
import org.eclipse.jetty.util.component.AggregateLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/* ------------------------------------------------------------ */
/** A handle that uses regular expressions to select the target.
* <p>
* This handler applies a list of regex to target name mappings to the URIs of requests.
* If the regex matches the URI, then the mapped target name is used in the nested
* call to {@link #doScope(String, Request, HttpServletRequest, HttpServletResponse)}.
* <p>
* This handler should be installed as the first handler in a Context. It can be configured
* either with direct calls to {@link #addPatternTarget(String, String)} or by setting
* the context init parameters "org.eclipse.jetty.rewrite.handler.REGEX_MAPPINGS" to a comma
* separated list of strings in the format regex==target.
*/
public class RegexTargetHandler extends ScopedHandler
{
private final static Logger LOG = Log.getLogger(RegexTargetHandler.class);
public final static String REGEX_MAPPINGS="org.eclipse.jetty.rewrite.handler.REGEX_MAPPINGS";
static class RegexMapping
{
RegexMapping(String regex,String target)
{
_pattern=Pattern.compile(regex);
_target=target;
}
final Pattern _pattern;
final String _target;
public String toString()
{
return _pattern+"=="+_target;
}
}
final private List<RegexTargetHandler.RegexMapping> _patterns = new CopyOnWriteArrayList<RegexTargetHandler.RegexMapping>();
/* ------------------------------------------------------------ */
/** Add a pattern to target mapping.
* @param pattern The regular expression pattern to match.
* @param target The target (normally servlet name) to handle the request
*/
public void addPatternTarget(String pattern,String target)
{
_patterns.add(new RegexMapping(pattern,target));
}
/* ------------------------------------------------------------ */
@Override
protected void doStart() throws Exception
{
super.doStart();
Context context = ContextHandler.getCurrentContext();
if (context!=null)
{
String config=context.getInitParameter(REGEX_MAPPINGS);
LOG.debug("{}={}",REGEX_MAPPINGS,config);
String[] mappings=config.split("\\s*,\\s*");
for (String mapping : mappings)
{
mapping=mapping.trim();
String[] parts=mapping.split("\\s*==\\s*");
if (parts.length==2)
{
String pattern=parts[0];
String target=parts[1];
addPatternTarget(pattern,target);
}
else
LOG.warn("Bad regex mapping: "+mapping);
}
}
}
/* ------------------------------------------------------------ */
@Override
public void doScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
for (RegexTargetHandler.RegexMapping rm : _patterns)
{
Matcher m=rm._pattern.matcher(target);
if (m.matches())
{
String new_target = rm._target;
final String sp;
final String pi;
if (m.groupCount()==1&&target.endsWith(m.group(1)))
{
pi=m.group(1);
sp=target.substring(0,target.length()-pi.length());
}
else
{
sp=target;
pi=null;
}
baseRequest.setServletPath(sp);
baseRequest.setPathInfo(pi);
baseRequest.setAttribute("org.eclipse.jetty.servlet.REGEX_PATH",target);
super.nextScope(new_target,baseRequest,request,response);
return;
}
}
super.nextScope(target,baseRequest,request,response);
}
/* ------------------------------------------------------------ */
@Override
public void doHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
String path=(String)baseRequest.getAttribute("org.eclipse.jetty.servlet.REGEX_PATH");
if (path==null)
path=target;
else
baseRequest.setAttribute("org.eclipse.jetty.servlet.REGEX_PATH",null);
super.nextHandle(path,baseRequest,request,response);
}
/* ------------------------------------------------------------ */
public void dump(Appendable out, String indent) throws IOException
{
AggregateLifeCycle.dumpObject(out,this);
AggregateLifeCycle.dump(out,indent,_patterns,Collections.singletonList(getHandler()));
}
}

View File

@ -18,6 +18,7 @@ import java.util.regex.Matcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.server.Request;
/**
@ -88,15 +89,21 @@ public class RewriteRegexRule extends RegexRule implements Rule.ApplyURI
/* ------------------------------------------------------------ */
public void applyURI(Request request, String oldTarget, String newTarget) throws IOException
{
if (_query==null)
{
request.setRequestURI(newTarget);
if (_query!=null)
}
else
{
String query=(String)request.getAttribute("org.eclipse.jetty.rewrite.handler.RewriteRegexRule.Q");
if (_queryGroup||request.getQueryString()==null)
if (!_queryGroup && request.getQueryString()!=null)
query=request.getQueryString()+"&"+query;
HttpURI uri=new HttpURI(newTarget+"?"+query);
request.setUri(uri);
request.setRequestURI(newTarget);
request.setQueryString(query);
else
request.setQueryString(request.getQueryString()+"&"+query);
}
}

View File

@ -1,214 +0,0 @@
// ========================================================================
// Copyright (c) 2006-2009 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.rewrite.handler;
import static junit.framework.Assert.assertEquals;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.RequestDispatcher;
import javax.servlet.Servlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequestWrapper;
import javax.servlet.ServletResponseWrapper;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import junit.framework.Assert;
import org.eclipse.jetty.rewrite.handler.RegexTargetHandler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class RegexTargetHandlerTest
{
private static Server __server = new Server(0);
private static int __port;
@BeforeClass
public static void setup() throws Exception
{
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
__server.setHandler(context);
// Serve some hello world servlets
context.addServlet(DispatchServletServlet.class,"/dispatch/*");
context.addServlet(new ServletHolder("HelloAll",new HelloServlet("Hello World")),"/*");
context.addServlet(new ServletHolder("Italian",new HelloServlet("Buongiorno Mondo")),"/it/*");
context.addServlet(new ServletHolder("French", new HelloServlet("Bonjour le Monde")),"/fr/*");
RegexTargetHandler regexHandler=new RegexTargetHandler();
regexHandler.setHandler(context.getHandler());
context.setHandler(regexHandler);
context.getInitParams().put(RegexTargetHandler.REGEX_MAPPINGS,
" .*\\.fr==French, \n"+
"/ciao(/.*)$==Italian");
__server.start();
__port=__server.getConnectors()[0].getLocalPort();
}
@AfterClass
public static void shutdown() throws Exception
{
__server.stop();
}
@Test
public void testNormal() throws Exception
{
String[] response=getResponse("/normal");
assertEquals("HTTP/1.1 200 OK",response[0]);
assertEquals("Hello World",response[1]);
assertEquals("",response[2]);
assertEquals("/normal",response[3]);
response=getResponse("/it/info");
assertEquals("HTTP/1.1 200 OK",response[0]);
assertEquals("Buongiorno Mondo",response[1]);
assertEquals("/it",response[2]);
assertEquals("/info",response[3]);
}
@Test
public void testFullMatch() throws Exception
{
String[] response=getResponse("/some/thing.fr");
assertEquals("HTTP/1.1 200 OK",response[0]);
assertEquals("Bonjour le Monde",response[1]);
assertEquals("/some/thing.fr",response[2]);
assertEquals("null",response[3]);
}
@Test
public void testCaptureMatch() throws Exception
{
String[] response=getResponse("/ciao/info");
assertEquals("HTTP/1.1 200 OK",response[0]);
assertEquals("Buongiorno Mondo",response[1]);
assertEquals("/ciao",response[2]);
assertEquals("/info",response[3]);
}
@Test
public void testDispatchFullMatch() throws Exception
{
String[] response=getResponse("/dispatch/xxx?forward=/some/thing.fr");
assertEquals("HTTP/1.1 200 OK",response[0]);
assertEquals("Bonjour le Monde",response[1]);
assertEquals("/some/thing.fr",response[2]);
assertEquals("null",response[3]);
}
@Test
public void testDispatchCaptureMatch() throws Exception
{
String[] response=getResponse("/dispatch/xxx?forward=/ciao/info");
assertEquals("HTTP/1.1 200 OK",response[0]);
assertEquals("Buongiorno Mondo",response[1]);
assertEquals("/ciao",response[2]);
assertEquals("/info",response[3]);
}
private String[] getResponse(String uri) throws Exception
{
Socket socket = new Socket("127.0.0.1",__port);
PrintWriter out = new PrintWriter(socket.getOutputStream());
out.print("GET "+uri+" HTTP/1.0\r\n\r\n");
out.flush();
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String[] response=new String[4];
response[0]=in.readLine();
//System.err.println(response[0]);
String line=in.readLine();
while(line.length()>0)
line=in.readLine();
response[1]=in.readLine();
//System.err.println(response[1]);
response[2]=in.readLine();
//System.err.println(response[2]);
response[3]=in.readLine();
//System.err.println(response[3]);
socket.close();
return response;
}
public static class HelloServlet extends HttpServlet implements Servlet
{
final String _hello;
public HelloServlet(String hello)
{
_hello=hello;
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
response.setStatus(200);
response.getWriter().println(_hello);
response.getWriter().println(request.getServletPath());
response.getWriter().println(request.getPathInfo());
}
}
public static class DispatchServletServlet extends HttpServlet implements Servlet
{
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
RequestDispatcher dispatcher = null;
if(request.getParameter("include")!=null)
{
dispatcher = getServletContext().getRequestDispatcher(request.getParameter("include"));
dispatcher.include(new HttpServletRequestWrapper(request), new HttpServletResponseWrapper(response));
}
else if(request.getParameter("forward")!=null)
{
dispatcher = getServletContext().getRequestDispatcher(request.getParameter("forward"));
dispatcher.forward(new HttpServletRequestWrapper(request), new HttpServletResponseWrapper(response));
}
}
}
}

View File

@ -14,6 +14,10 @@ package org.eclipse.jetty.rewrite.handler;
import java.io.IOException;
import org.eclipse.jetty.http.HttpURI;
import org.eclipse.jetty.util.MultiMap;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.UrlEncoded;
import org.junit.Before;
import org.junit.Test;
@ -23,21 +27,21 @@ public class RewriteRegexRuleTest extends AbstractRuleTestCase
{
private String[][] _tests=
{
{"/foo/bar",null,".*","/replace","/replace",null},
{"/foo/bar","n=v",".*","/replace","/replace","n=v"},
{"/foo/bar",null,"/xxx.*","/replace",null,null},
{"/foo/bar",null,"/(.*)/(.*)","/$2/$1/xxx","/bar/foo/xxx",null},
{"/foo/bar",null,"/(.*)/(.*)","/test?p2=$2&p1=$1","/test","p2=bar&p1=foo"},
{"/foo/bar","n=v","/(.*)/(.*)","/test?p2=$2&p1=$1","/test","n=v&p2=bar&p1=foo"},
{"/foo/bar",null,"/(.*)/(.*)","/foo/bar?p2=$2&p1=$1","/foo/bar","p2=bar&p1=foo"},
{"/foo/bar","n=v","/(.*)/(.*)","/foo/bar?p2=$2&p1=$1","/foo/bar","n=v&p2=bar&p1=foo"},
{"/foo/bar",null,"/(foo)/(.*)(bar)","/$3/$1/xxx$2","/bar/foo/xxx",null},
{"/foo/$bar",null,".*","/$replace","/$replace",null},
{"/foo/$bar",null,"/foo/(.*)","/$1/replace","/$bar/replace",null},
{"/foo/bar/info",null,"/foo/(NotHere)?([^/]*)/(.*)","/$3/other?p1=$2","/info/other","p1=bar"},
{"/foo/bar/info",null,"/foo/(NotHere)?([^/]*)/(.*)","/$3/other?p1=$2&$Q","/info/other","p1=bar&"},
{"/foo/bar/info","n=v","/foo/(NotHere)?([^/]*)/(.*)","/$3/other?p1=$2&$Q","/info/other","p1=bar&n=v"},
{"/foo/bar/info","n=v","/foo/(NotHere)?([^/]*)/(.*)","/$3/other?p1=$2","/info/other","n=v&p1=bar"},
{"/foo0/bar",null,".*","/replace","/replace",null},
{"/foo1/bar","n=v",".*","/replace","/replace","n=v"},
{"/foo2/bar",null,"/xxx.*","/replace",null,null},
{"/foo3/bar",null,"/(.*)/(.*)","/$2/$1/xxx","/bar/foo3/xxx",null},
{"/foo4/bar",null,"/(.*)/(.*)","/test?p2=$2&p1=$1","/test","p2=bar&p1=foo4"},
{"/foo5/bar","n=v","/(.*)/(.*)","/test?p2=$2&p1=$1","/test","n=v&p2=bar&p1=foo5"},
{"/foo6/bar",null,"/(.*)/(.*)","/foo6/bar?p2=$2&p1=$1","/foo6/bar","p2=bar&p1=foo6"},
{"/foo7/bar","n=v","/(.*)/(.*)","/foo7/bar?p2=$2&p1=$1","/foo7/bar","n=v&p2=bar&p1=foo7"},
{"/foo8/bar",null,"/(foo8)/(.*)(bar)","/$3/$1/xxx$2","/bar/foo8/xxx",null},
{"/foo9/$bar",null,".*","/$replace","/$replace",null},
{"/fooA/$bar",null,"/fooA/(.*)","/$1/replace","/$bar/replace",null},
{"/fooB/bar/info",null,"/fooB/(NotHere)?([^/]*)/(.*)","/$3/other?p1=$2","/info/other","p1=bar"},
{"/fooC/bar/info",null,"/fooC/(NotHere)?([^/]*)/(.*)","/$3/other?p1=$2&$Q","/info/other","p1=bar&"},
{"/fooD/bar/info","n=v","/fooD/(NotHere)?([^/]*)/(.*)","/$3/other?p1=$2&$Q","/info/other","p1=bar&n=v"},
{"/fooE/bar/info","n=v","/fooE/(NotHere)?([^/]*)/(.*)","/$3/other?p1=$2","/info/other","n=v&p1=bar"},
};
private RewriteRegexRule _rule;
@ -53,21 +57,36 @@ public class RewriteRegexRuleTest extends AbstractRuleTestCase
{
for (String[] test : _tests)
{
reset();
_request.setRequestURI(null);
String t=test[0]+"?"+test[1]+">"+test[2]+"|"+test[3];
_rule.setRegex(test[2]);
_rule.setReplacement(test[3]);
_request.setRequestURI(test[0]);
_request.setQueryString(test[1]);
_request.getAttributes().clearAttributes();
_request.setUri(new HttpURI(test[0]+(test[1]==null?"":("?"+test[1]))));
_request.getRequestURI();
String result = _rule.matchAndApply(test[0], _request, _response);
assertEquals(t, test[4], result);
_rule.applyURI(_request,test[0],result);
if (result!=null)
{
assertEquals(t,test[4], _request.getRequestURI());
assertEquals(t,test[5], _request.getQueryString());
}
if (test[5]!=null)
{
MultiMap<String> params=new MultiMap<String>();
UrlEncoded.decodeTo(test[5],params,StringUtil.__UTF8);
for (String n:params.keySet())
assertEquals(params.getString(n),_request.getParameter(n));
}
}
}
@Test
@ -78,6 +97,7 @@ public class RewriteRegexRuleTest extends AbstractRuleTestCase
container.addRule(_rule);
for (String[] test : _tests)
{
reset();
String t=test[0]+"?"+test[1]+">"+test[2]+"|"+test[3];
_rule.setRegex(test[2]);
_rule.setReplacement(test[3]);

View File

@ -385,7 +385,7 @@ public class ResponseTest
{
String[][] tests={
{"/other/location?name=value","http://myhost:8888/other/location;jsessionid=12345?name=value"},
{"/other/location","http://myhost:8888/other/location"},
/* {"/other/location","http://myhost:8888/other/location"},
{"/other/l%20cation","http://myhost:8888/other/l%20cation"},
{"location","http://myhost:8888/path/location"},
{"./location","http://myhost:8888/path/location"},
@ -393,7 +393,8 @@ public class ResponseTest
{"/other/l%20cation","http://myhost:8888/other/l%20cation"},
{"l%20cation","http://myhost:8888/path/l%20cation"},
{"./l%20cation","http://myhost:8888/path/l%20cation"},
{"../l%20cation","http://myhost:8888/l%20cation"},
{"../l%20cation","http://myhost:8888/l%20cation"},*/
{"../locati%C3%abn","http://myhost:8888/locati%C3%ABn"},
};
for (int i=1;i<tests.length;i++)

View File

@ -99,8 +99,6 @@ public class SSLEngineTest
connector.setRequestHeaderSize(512);
server.setConnectors(new Connector[]{connector });
server.setHandler(new HelloWorldHandler());
server.start();
}
@AfterClass
@ -110,9 +108,14 @@ public class SSLEngineTest
server.join();
}
@Test
public void testBigResponse() throws Exception
{
server.stop();
server.setHandler(new HelloWorldHandler());
server.start();
SSLContext ctx=SSLContext.getInstance("TLS");
ctx.init(null,SslContextFactory.TRUST_ALL_CERTS,new java.security.SecureRandom());
@ -123,7 +126,7 @@ public class SSLEngineTest
String request =
"GET /?dump=102400 HTTP/1.1\r\n"+
"Host: localhost:8080\r\n"+
"Host: localhost:"+port+"\r\n"+
"Connection: close\r\n"+
"\r\n";
@ -138,6 +141,10 @@ public class SSLEngineTest
@Test
public void testRequestJettyHttps() throws Exception
{
server.stop();
server.setHandler(new HelloWorldHandler());
server.start();
final int loops=10;
final int numConns=10;
@ -204,8 +211,7 @@ public class SSLEngineTest
@Test
public void testServletPost() throws Exception
{
stopServer();
server.stop();
StreamHandler handler = new StreamHandler();
server.setHandler(handler);
server.start();
@ -308,6 +314,7 @@ public class SSLEngineTest
{
ServletOutputStream out=response.getOutputStream();
byte[] buf = new byte[Integer.valueOf(request.getParameter("dump"))];
// System.err.println("DUMP "+buf.length);
for (int i=0;i<buf.length;i++)
buf[i]=(byte)('0'+(i%10));
out.write(buf);

View File

@ -1240,7 +1240,7 @@ public class ServletHandler extends ScopedHandler
{
if(LOG.isDebugEnabled())
LOG.debug("Not Found "+request.getRequestURI());
response.sendError(HttpServletResponse.SC_NOT_FOUND);
//Override to send an error back, eg with: response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
/* ------------------------------------------------------------ */

View File

@ -150,21 +150,6 @@ public class GzipFilter extends UserAgentFilter
{
}
/* ------------------------------------------------------------ */
public String selectCompression(String encodingHeader)
{
// TODO, this could be a little more robust.
// prefer gzip over deflate
if (encodingHeader!=null)
{
if (encodingHeader.toLowerCase().contains(GZIP))
return GZIP;
if (encodingHeader.toLowerCase().contains(DEFLATE))
return DEFLATE;
}
return null;
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.servlets.UserAgentFilter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
@ -176,7 +161,6 @@ public class GzipFilter extends UserAgentFilter
HttpServletRequest request=(HttpServletRequest)req;
HttpServletResponse response=(HttpServletResponse)res;
String ae = request.getHeader("accept-encoding");
String compressionType = selectCompression(request.getHeader("accept-encoding"));
if (compressionType!=null && !response.containsHeader("Content-Encoding") && !HttpMethods.HEAD.equalsIgnoreCase(request.getMethod()))
{
@ -223,6 +207,21 @@ public class GzipFilter extends UserAgentFilter
}
}
/* ------------------------------------------------------------ */
private String selectCompression(String encodingHeader)
{
// TODO, this could be a little more robust.
// prefer gzip over deflate
if (encodingHeader!=null)
{
if (encodingHeader.toLowerCase().contains(GZIP))
return GZIP;
else if (encodingHeader.toLowerCase().contains(DEFLATE))
return DEFLATE;
}
return null;
}
protected CompressedResponseWrapper createWrappedResponse(HttpServletRequest request, HttpServletResponse response, final String compressionType)
{
CompressedResponseWrapper wrappedResponse = null;
@ -304,7 +303,7 @@ public class GzipFilter extends UserAgentFilter
}
/**
* Checks to see if the UserAgent is excluded
* Checks to see if the userAgent is excluded
*
* @param ua
* the user agent
@ -322,7 +321,7 @@ public class GzipFilter extends UserAgentFilter
return true;
}
}
else if (_excludedAgentPatterns != null)
if (_excludedAgentPatterns != null)
{
for (Pattern pattern : _excludedAgentPatterns)
{
@ -337,9 +336,9 @@ public class GzipFilter extends UserAgentFilter
}
/**
* Checks to see if the Path is excluded
* Checks to see if the path is excluded
*
* @param ua
* @param requestURI
* the request uri
* @return boolean true if excluded
*/
@ -347,6 +346,16 @@ public class GzipFilter extends UserAgentFilter
{
if (requestURI == null)
return false;
if (_excludedPaths != null)
{
for (String excludedPath : _excludedPaths)
{
if (requestURI.startsWith(excludedPath))
{
return true;
}
}
}
if (_excludedPathPatterns != null)
{
for (Pattern pattern : _excludedPathPatterns)

View File

@ -33,8 +33,7 @@ public class GzipFilterDefaultTest
String[][] data = new String[][]
{
{ GzipFilter.GZIP },
{ GzipFilter.DEFLATE }
};
{ GzipFilter.DEFLATE } };
return Arrays.asList(data);
}
@ -185,4 +184,72 @@ public class GzipFilterDefaultTest
tester.stop();
}
}
@Test
public void testUserAgentExclusionByExcludedAgentPatterns() throws Exception
{
GzipTester tester = new GzipTester(testingdir,compressionType);
FilterHolder holder = tester.setContentServlet(DefaultServlet.class);
holder.setInitParameter("excludedAgents","bar");
holder.setInitParameter("excludeAgentPatterns","fo.*");
tester.setUserAgent("foo");
int filesize = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE * 4;
tester.prepareServerFile("file.txt",filesize);
try
{
tester.start();
tester.assertIsResponseNotGzipCompressed("file.txt",filesize,HttpStatus.OK_200);
}
finally
{
tester.stop();
}
}
@Test
public void testExcludePaths() throws Exception
{
GzipTester tester = new GzipTester(testingdir,compressionType);
FilterHolder holder = tester.setContentServlet(DefaultServlet.class);
holder.setInitParameter("excludePaths","/context/");
int filesize = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE * 4;
tester.prepareServerFile("file.txt",filesize);
try
{
tester.start();
tester.assertIsResponseNotGzipCompressed("file.txt",filesize,HttpStatus.OK_200);
}
finally
{
tester.stop();
}
}
@Test
public void testExcludePathPatterns() throws Exception
{
GzipTester tester = new GzipTester(testingdir,compressionType);
FilterHolder holder = tester.setContentServlet(DefaultServlet.class);
holder.setInitParameter("excludePathPatterns","/cont.*");
int filesize = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE * 4;
tester.prepareServerFile("file.txt",filesize);
try
{
tester.start();
tester.assertIsResponseNotGzipCompressed("file.txt",filesize,HttpStatus.OK_200);
}
finally
{
tester.stop();
}
}
}

View File

@ -13,11 +13,7 @@
<name>Jetty :: SPDY :: Parent</name>
<properties>
<!--
npn version only needs to change when there are changes in that binary, not
with each and every release.
-->
<npn.version>7.6.2.v20120308</npn.version>
<npn.version>1.0.0.v20120402</npn.version>
</properties>
<modules>

View File

@ -12,8 +12,9 @@
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>

View File

@ -68,8 +68,9 @@ public interface IStream extends Stream
* of true puts the stream into closed state.</p>
*
* @param close whether the close state should be updated
* @param local whether the close is local or remote
*/
public void updateCloseState(boolean close);
public void updateCloseState(boolean close, boolean local);
/**
* <p>Processes the given control frame,

View File

@ -18,7 +18,6 @@ package org.eclipse.jetty.spdy;
import java.nio.ByteBuffer;
import java.nio.channels.InterruptedByTimeoutException;
import java.util.Deque;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
@ -62,12 +61,12 @@ import org.eclipse.jetty.spdy.frames.SynStreamFrame;
import org.eclipse.jetty.spdy.frames.WindowUpdateFrame;
import org.eclipse.jetty.spdy.generator.Generator;
import org.eclipse.jetty.spdy.parser.Parser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class StandardSession implements ISession, Parser.Listener, Handler<StandardSession.FrameBytes>
{
private static final Logger logger = LoggerFactory.getLogger(Session.class);
private static final Logger logger = Log.getLogger(Session.class);
private static final ThreadLocal<Integer> handlerInvocations = new ThreadLocal<Integer>()
{
@Override
@ -79,7 +78,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
private final List<Listener> listeners = new CopyOnWriteArrayList<>();
private final ConcurrentMap<Integer, IStream> streams = new ConcurrentHashMap<>();
private final Deque<FrameBytes> queue = new LinkedList<>();
private final LinkedList<FrameBytes> queue = new LinkedList<>();
private final ByteBufferPool bufferPool;
private final Executor threadPool;
private final ScheduledExecutorService scheduler;
@ -399,6 +398,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
private void onSyn(SynStreamFrame frame)
{
IStream stream = newStream(frame);
stream.updateCloseState(frame.isClose(), false);
logger.debug("Opening {}", stream);
int streamId = frame.getStreamId();
IStream existing = streams.putIfAbsent(streamId, stream);
@ -430,6 +430,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
private IStream createStream(SynStreamFrame synStream, StreamFrameListener listener)
{
IStream stream = newStream(synStream);
stream.updateCloseState(synStream.isClose(), true);
stream.setStreamFrameListener(listener);
if (streams.putIfAbsent(synStream.getStreamId(), stream) != null)
{
@ -732,10 +733,15 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
{
ByteBuffer buffer = generator.control(frame);
logger.debug("Queuing {} on {}", frame, stream);
ControlFrameBytes<C> frameBytes = new ControlFrameBytes<>(handler, context, frame, buffer);
ControlFrameBytes<C> frameBytes = new ControlFrameBytes<>(stream, handler, context, frame, buffer);
if (timeout > 0)
frameBytes.task = scheduler.schedule(frameBytes, timeout, unit);
enqueueLast(frameBytes);
// Special handling for PING frames, they must be sent as soon as possible
if (ControlFrameType.PING == frame.getType())
prepend(frameBytes);
else
append(frameBytes);
}
flush();
@ -766,10 +772,10 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
public <C> void data(IStream stream, DataInfo dataInfo, long timeout, TimeUnit unit, Handler<C> handler, C context)
{
logger.debug("Queuing {} on {}", dataInfo, stream);
DataFrameBytes<C> frameBytes = new DataFrameBytes<>(handler, context, stream, dataInfo);
DataFrameBytes<C> frameBytes = new DataFrameBytes<>(stream, handler, context, dataInfo);
if (timeout > 0)
frameBytes.task = scheduler.schedule(frameBytes, timeout, unit);
enqueueLast(frameBytes);
append(frameBytes);
flush();
}
@ -781,56 +787,73 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
@Override
public void flush()
{
FrameBytes frameBytes;
ByteBuffer buffer;
FrameBytes frameBytes = null;
ByteBuffer buffer = null;
synchronized (queue)
{
if (flushing)
if (flushing || queue.isEmpty())
return;
frameBytes = queue.poll();
if (frameBytes == null)
return;
FrameBytes stalled = null;
while (true)
Set<IStream> stalledStreams = null;
for (int i = 0; i < queue.size(); ++i)
{
frameBytes = queue.get(i);
if (stalledStreams != null && stalledStreams.contains(frameBytes.getStream()))
continue;
buffer = frameBytes.getByteBuffer();
if (buffer != null)
{
queue.remove(i);
break;
// We are stalled: enqueue as last so other frames can be flushed
enqueueLast(frameBytes);
if (stalled == null)
stalled = frameBytes;
else if (stalled == frameBytes)
return;
logger.debug("Flush stalled for {}, {} frame(s) in queue", frameBytes, queue.size());
frameBytes = queue.poll();
}
if (stalledStreams == null)
stalledStreams = new HashSet<>();
stalledStreams.add(frameBytes.getStream());
logger.debug("Flush stalled for {}, {} frame(s) in queue", frameBytes, queue.size());
}
if (buffer == null)
return;
flushing = true;
logger.debug("Flushing {}, {} frame(s) in queue", frameBytes, queue.size());
}
logger.debug("Writing {} frame bytes of {}", buffer.remaining(), frameBytes);
write(buffer, this, frameBytes);
}
private void enqueueLast(FrameBytes frameBytes)
private void append(FrameBytes frameBytes)
{
// TODO: handle priority; e.g. use queues to prioritize the buffers ?
synchronized (queue)
{
queue.offerLast(frameBytes);
int index = queue.size();
while (index > 0)
{
FrameBytes element = queue.get(index - 1);
if (element.compareTo(frameBytes) >= 0)
break;
--index;
}
queue.add(index, frameBytes);
}
}
private void enqueueFirst(FrameBytes frameBytes)
private void prepend(FrameBytes frameBytes)
{
synchronized (queue)
{
queue.offerFirst(frameBytes);
int index = 0;
while (index < queue.size())
{
FrameBytes element = queue.get(index);
if (element.compareTo(frameBytes) <= 0)
break;
++index;
}
queue.add(index, frameBytes);
}
}
@ -854,12 +877,13 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
protected void write(ByteBuffer buffer, Handler<FrameBytes> handler, FrameBytes frameBytes)
{
if (controller != null)
{
logger.debug("Writing {} frame bytes of {}", buffer.remaining(), frameBytes);
controller.write(buffer, handler, frameBytes);
}
}
private <C> void complete(final Handler<C> handler, final C context)
{
if (handler != null)
{
// Applications may send and queue up a lot of frames and
// if we call Handler.completed() only synchronously we risk
@ -873,6 +897,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
@Override
public void run()
{
if (handler != null)
notifyHandlerCompleted(handler, context);
flush();
}
@ -883,6 +908,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
handlerInvocations.set(invocations + 1);
try
{
if (handler != null)
notifyHandlerCompleted(handler, context);
flush();
}
@ -892,7 +918,6 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
}
}
}
}
private <C> void notifyHandlerCompleted(Handler<C> handler, C context)
{
@ -920,8 +945,10 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
}
}
public interface FrameBytes
public interface FrameBytes extends Comparable<FrameBytes>
{
public IStream getStream();
public abstract ByteBuffer getByteBuffer();
public abstract void complete();
@ -929,16 +956,31 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
private abstract class AbstractFrameBytes<C> implements FrameBytes, Runnable
{
private final IStream stream;
private final Handler<C> handler;
private final C context;
protected volatile ScheduledFuture<?> task;
protected AbstractFrameBytes(Handler<C> handler, C context)
protected AbstractFrameBytes(IStream stream, Handler<C> handler, C context)
{
this.stream = stream;
this.handler = handler;
this.context = context;
}
@Override
public IStream getStream()
{
return stream;
}
@Override
public int compareTo(FrameBytes that)
{
// If this.stream.priority > that.stream.priority => -1 (this.stream has less priority than that.stream)
return that.getStream().getPriority() - getStream().getPriority();
}
@Override
public void complete()
{
@ -966,9 +1008,9 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
private final ControlFrame frame;
private final ByteBuffer buffer;
private ControlFrameBytes(Handler<C> handler, C context, ControlFrame frame, ByteBuffer buffer)
private ControlFrameBytes(IStream stream, Handler<C> handler, C context, ControlFrame frame, ByteBuffer buffer)
{
super(handler, context);
super(stream, handler, context);
this.frame = frame;
this.buffer = buffer;
}
@ -1003,15 +1045,13 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
private class DataFrameBytes<C> extends AbstractFrameBytes<C>
{
private final IStream stream;
private final DataInfo dataInfo;
private int size;
private volatile ByteBuffer buffer;
private DataFrameBytes(Handler<C> handler, C context, IStream stream, DataInfo dataInfo)
private DataFrameBytes(IStream stream, Handler<C> handler, C context, DataInfo dataInfo)
{
super(handler, context);
this.stream = stream;
super(stream, handler, context);
this.dataInfo = dataInfo;
}
@ -1020,6 +1060,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
{
try
{
IStream stream = getStream();
int windowSize = stream.getWindowSize();
if (windowSize <= 0)
return null;
@ -1042,6 +1083,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
public void complete()
{
bufferPool.release(buffer);
IStream stream = getStream();
stream.updateWindowSize(-size);
if (dataInfo.available() > 0)
@ -1049,12 +1091,12 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
// We have written a frame out of this DataInfo, but there is more to write.
// We need to keep the correct ordering of frames, to avoid that another
// DataInfo for the same stream is written before this one is finished.
enqueueFirst(this);
prepend(this);
}
else
{
super.complete();
stream.updateCloseState(dataInfo.isClose());
stream.updateCloseState(dataInfo.isClose(), true);
if (stream.isClosed())
removeStream(stream);
}
@ -1063,7 +1105,7 @@ public class StandardSession implements ISession, Parser.Listener, Handler<Stand
@Override
public String toString()
{
return String.format("DATA bytes @%x available=%d consumed=%d on %s", dataInfo.hashCode(), dataInfo.available(), dataInfo.consumed(), stream);
return String.format("DATA bytes @%x available=%d consumed=%d on %s", dataInfo.hashCode(), dataInfo.available(), dataInfo.consumed(), getStream());
}
}
}

View File

@ -39,27 +39,25 @@ import org.eclipse.jetty.spdy.frames.HeadersFrame;
import org.eclipse.jetty.spdy.frames.SynReplyFrame;
import org.eclipse.jetty.spdy.frames.SynStreamFrame;
import org.eclipse.jetty.spdy.frames.WindowUpdateFrame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class StandardStream implements IStream
{
private static final Logger logger = LoggerFactory.getLogger(Stream.class);
private static final Logger logger = Log.getLogger(Stream.class);
private final Map<String, Object> attributes = new ConcurrentHashMap<>();
private final SynStreamFrame frame;
private final ISession session;
private final AtomicInteger windowSize;
private volatile StreamFrameListener listener;
private volatile boolean opened;
private volatile boolean halfClosed;
private volatile boolean closed;
private volatile OpenState openState = OpenState.SYN_SENT;
private volatile CloseState closeState = CloseState.OPENED;
public StandardStream(SynStreamFrame frame, ISession session, int windowSize)
{
this.frame = frame;
this.session = session;
this.windowSize = new AtomicInteger(windowSize);
this.halfClosed = frame.isClose();
}
@Override
@ -95,7 +93,8 @@ public class StandardStream implements IStream
public boolean isHalfClosed()
{
return halfClosed;
CloseState closeState = this.closeState;
return closeState == CloseState.LOCALLY_CLOSED || closeState == CloseState.REMOTELY_CLOSED;
}
@Override
@ -123,14 +122,38 @@ public class StandardStream implements IStream
}
@Override
public void updateCloseState(boolean close)
public void updateCloseState(boolean close, boolean local)
{
if (close)
{
if (isHalfClosed())
closed = true;
switch (closeState)
{
case OPENED:
{
closeState = local ? CloseState.LOCALLY_CLOSED : CloseState.REMOTELY_CLOSED;
break;
}
case LOCALLY_CLOSED:
{
if (local)
throw new IllegalStateException();
else
halfClosed = true;
closeState = CloseState.CLOSED;
break;
}
case REMOTELY_CLOSED:
{
if (local)
closeState = CloseState.CLOSED;
else
throw new IllegalStateException();
break;
}
default:
{
throw new IllegalStateException();
}
}
}
}
@ -141,14 +164,14 @@ public class StandardStream implements IStream
{
case SYN_STREAM:
{
opened = true;
openState = OpenState.SYN_RECV;
break;
}
case SYN_REPLY:
{
opened = true;
openState = OpenState.REPLY_RECV;
SynReplyFrame synReply = (SynReplyFrame)frame;
updateCloseState(synReply.isClose());
updateCloseState(synReply.isClose(), false);
ReplyInfo replyInfo = new ReplyInfo(synReply.getHeaders(), synReply.isClose());
notifyOnReply(replyInfo);
break;
@ -156,7 +179,7 @@ public class StandardStream implements IStream
case HEADERS:
{
HeadersFrame headers = (HeadersFrame)frame;
updateCloseState(headers.isClose());
updateCloseState(headers.isClose(), false);
HeadersInfo headersInfo = new HeadersInfo(headers.getHeaders(), headers.isClose(), headers.isResetCompression());
notifyOnHeaders(headersInfo);
break;
@ -183,13 +206,13 @@ public class StandardStream implements IStream
@Override
public void process(DataFrame frame, ByteBuffer data)
{
if (!opened)
if (!canReceive())
{
session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR));
return;
}
updateCloseState(frame.isClose());
updateCloseState(frame.isClose(), false);
ByteBufferDataInfo dataInfo = new ByteBufferDataInfo(data, frame.isClose(), frame.isCompress())
{
@ -286,7 +309,8 @@ public class StandardStream implements IStream
@Override
public void reply(ReplyInfo replyInfo, long timeout, TimeUnit unit, Handler<Void> handler)
{
updateCloseState(replyInfo.isClose());
openState = OpenState.REPLY_SENT;
updateCloseState(replyInfo.isClose(), true);
SynReplyFrame frame = new SynReplyFrame(session.getVersion(), replyInfo.getFlags(), getId(), replyInfo.getHeaders());
session.control(this, frame, timeout, unit, handler, null);
}
@ -302,6 +326,17 @@ public class StandardStream implements IStream
@Override
public void data(DataInfo dataInfo, long timeout, TimeUnit unit, Handler<Void> handler)
{
if (!canSend())
{
session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR));
throw new IllegalStateException("Protocol violation: cannot send a DATA frame before a SYN_REPLY frame");
}
if (isLocallyClosed())
{
session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR));
throw new IllegalStateException("Protocol violation: cannot send a DATA frame on a closed stream");
}
// Cannot update the close state here, because the data that we send may
// be flow controlled, so we need the stream to update the window size.
session.data(this, dataInfo, timeout, unit, handler, null);
@ -318,7 +353,18 @@ public class StandardStream implements IStream
@Override
public void headers(HeadersInfo headersInfo, long timeout, TimeUnit unit, Handler<Void> handler)
{
updateCloseState(headersInfo.isClose());
if (!canSend())
{
session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR));
throw new IllegalStateException("Protocol violation: cannot send a HEADERS frame before a SYN_REPLY frame");
}
if (isLocallyClosed())
{
session.rst(new RstInfo(getId(), StreamStatus.PROTOCOL_ERROR));
throw new IllegalStateException("Protocol violation: cannot send a HEADERS frame on a closed stream");
}
updateCloseState(headersInfo.isClose(), true);
HeadersFrame frame = new HeadersFrame(session.getVersion(), headersInfo.getFlags(), getId(), headersInfo.getHeaders());
session.control(this, frame, timeout, unit, handler, null);
}
@ -326,12 +372,40 @@ public class StandardStream implements IStream
@Override
public boolean isClosed()
{
return closed;
return closeState == CloseState.CLOSED;
}
private boolean isLocallyClosed()
{
CloseState closeState = this.closeState;
return closeState == CloseState.LOCALLY_CLOSED || closeState == CloseState.CLOSED;
}
@Override
public String toString()
{
return String.format("stream=%d v%d closed=%s", getId(), session.getVersion(), isClosed() ? "true" : isHalfClosed() ? "half" : "false");
return String.format("stream=%d v%d %s", getId(), session.getVersion(), closeState);
}
private boolean canSend()
{
OpenState openState = this.openState;
return openState == OpenState.SYN_SENT || openState == OpenState.REPLY_RECV || openState == OpenState.REPLY_SENT;
}
private boolean canReceive()
{
OpenState openState = this.openState;
return openState == OpenState.SYN_RECV || openState == OpenState.REPLY_RECV || openState == OpenState.REPLY_SENT;
}
private enum OpenState
{
SYN_SENT, SYN_RECV, REPLY_SENT, REPLY_RECV
}
private enum CloseState
{
OPENED, LOCALLY_CLOSED, REMOTELY_CLOSED, CLOSED
}
}

View File

@ -18,8 +18,8 @@ package org.eclipse.jetty.spdy.api;
import java.util.EventListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
* <p>A {@link SessionFrameListener} is the passive counterpart of a {@link Session} and receives events happening
@ -122,7 +122,7 @@ public interface SessionFrameListener extends EventListener
*/
public static class Adapter implements SessionFrameListener
{
private static final Logger logger = LoggerFactory.getLogger(Adapter.class);
private static final Logger logger = Log.getLogger(Adapter.class);
@Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)

View File

@ -65,7 +65,7 @@ public class SettingsGenerator extends ControlFrameGenerator
case SPDY.V2:
{
// In v2 the format is 24 bits of ID + 8 bits of flag
int idAndFlags = (id << 8) + flags;
int idAndFlags = (id << 8) + (flags & 0xFF);
// A bug in the Chromium implementation forces v2 to have
// the 3 ID bytes little endian, so we swap first and third
int result = idAndFlags & 0x00_FF_00_FF;

View File

@ -58,6 +58,10 @@ public class GoAwayBodyParser extends ControlFrameBodyParser
state = State.STATUS_CODE;
break;
}
default:
{
throw new IllegalStateException();
}
}
}
else
@ -87,6 +91,10 @@ public class GoAwayBodyParser extends ControlFrameBodyParser
state = State.STATUS_CODE;
break;
}
default:
{
throw new IllegalStateException();
}
}
}
break;

View File

@ -27,12 +27,12 @@ import org.eclipse.jetty.spdy.StreamException;
import org.eclipse.jetty.spdy.api.SessionStatus;
import org.eclipse.jetty.spdy.frames.ControlFrame;
import org.eclipse.jetty.spdy.frames.DataFrame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class Parser
{
private static final Logger logger = LoggerFactory.getLogger(Parser.class);
private static final Logger logger = Log.getLogger(Parser.class);
private final List<Listener> listeners = new CopyOnWriteArrayList<>();
private final ControlFrameParser controlFrameParser;
private final DataFrameParser dataFrameParser;

View File

@ -22,7 +22,6 @@ import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import org.eclipse.jetty.spdy.api.Handler;
import org.eclipse.jetty.spdy.api.SPDY;
@ -94,17 +93,15 @@ public class AsyncTimeoutTest
Generator generator = new Generator(new StandardByteBufferPool(), new StandardCompressionFactory.StandardCompressor());
Session session = new StandardSession(SPDY.V2, bufferPool, threadPool, scheduler, new TestController(), null, 1, null, generator)
{
private final AtomicInteger flushes = new AtomicInteger();
@Override
public void flush()
protected void write(ByteBuffer buffer, Handler<FrameBytes> handler, FrameBytes frameBytes)
{
try
{
int flushes = this.flushes.incrementAndGet();
if (flushes == 3)
// Wait if we're writing the data frame (control frame's first byte is 0x80)
if (buffer.get(0) == 0)
unit.sleep(2 * timeout);
super.flush();
super.write(buffer, handler, frameBytes);
}
catch (InterruptedException x)
{

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.eclipse.jetty.spdy</groupId>
<artifactId>spdy-parent</artifactId>
@ -9,6 +10,7 @@
<artifactId>spdy-jetty-http-webapp</artifactId>
<packaging>war</packaging>
<name>Jetty :: SPDY :: Jetty HTTP Web Application</name>
<build>
<plugins>
<plugin>
@ -29,7 +31,6 @@
</executions>
</plugin>
<!--
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
@ -41,7 +42,7 @@
-Dlog4j.configuration=file://${basedir}/src/main/resources/log4j.properties
-Xbootclasspath/p:${settings.localRepository}/org/mortbay/jetty/npn/npn-boot/${project.version}/npn-boot-${project.version}.jar
</jvmArgs>
<jettyXml>${basedir}/src/main/config/jetty-spdy.xml</jettyXml>
<jettyXml>${basedir}/src/main/config/etc/jetty-spdy.xml</jettyXml>
<contextPath>/</contextPath>
</configuration>
<dependencies>

View File

@ -9,13 +9,6 @@
<Set name="trustStore">src/main/resources/truststore.jks</Set>
<Set name="trustStorePassword">storepwd</Set>
<Set name="protocol">TLSv1</Set>
<Set name="includeProtocols">
<Array type="java.lang.String">
<Item>TLSv1</Item>
<Item>TLSv1.1</Item>
<Item>TLSv1.2</Item>
</Array>
</Set>
</New>
<Call name="addConnector">

View File

@ -9,6 +9,7 @@
<modelVersion>4.0.0</modelVersion>
<artifactId>spdy-jetty-http</artifactId>
<name>Jetty :: SPDY :: Jetty HTTP Layer</name>
<build>
<plugins>
<plugin>
@ -28,7 +29,7 @@
<version>${npn.version}</version>
<type>jar</type>
<overWrite>false</overWrite>
<outputDirectory>${build.directory}/npn</outputDirectory>
<outputDirectory>${project.build.directory}/npn</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
@ -38,27 +39,12 @@
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
<argLine>-Xbootclasspath/p:${build.directory}/npn/npn-boot-${npn.version}.jar </argLine>
<argLine>-Xbootclasspath/p:${project.build.directory}/npn/npn-boot-${npn.version}.jar</argLine>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>eclipse-release</id>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty.spdy</groupId>
@ -82,4 +68,5 @@
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -50,13 +50,14 @@ import org.eclipse.jetty.spdy.api.DataInfo;
import org.eclipse.jetty.spdy.api.Headers;
import org.eclipse.jetty.spdy.api.ReplyInfo;
import org.eclipse.jetty.spdy.api.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implements AsyncConnection
{
private static final Logger logger = LoggerFactory.getLogger(ServerHTTPSPDYAsyncConnection.class);
private static final Logger logger = Log.getLogger(ServerHTTPSPDYAsyncConnection.class);
private static final ByteBuffer ZERO_BYTES = ByteBuffer.allocate(0);
private static final DataInfo END_OF_CONTENT = new ByteBufferDataInfo(ZERO_BYTES, true);
private final Queue<Runnable> tasks = new LinkedList<>();
private final BlockingQueue<DataInfo> dataInfos = new LinkedBlockingQueue<>();
@ -65,7 +66,6 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
private Headers headers; // No need for volatile, guarded by state
private DataInfo dataInfo; // No need for volatile, guarded by state
private NIOBuffer buffer; // No need for volatile, guarded by state
private boolean complete; // No need for volatile, guarded by state
private volatile State state = State.INITIAL;
private boolean dispatched; // Guarded by synchronization on tasks
@ -160,7 +160,7 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
logger.debug("HTTP > {} {} {}", new Object[]{m, u, v});
startRequest(new ByteArrayBuffer(m), new ByteArrayBuffer(u), new ByteArrayBuffer(v));
state = State.HEADERS;
updateState(State.HEADERS);
handle();
break;
}
@ -261,6 +261,12 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
{
}
private void updateState(State newState)
{
logger.debug("State update {} -> {}", state, newState);
state = newState;
}
public void beginRequest(final Headers headers)
{
this.headers = headers.isEmpty() ? null : headers;
@ -270,7 +276,7 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
public void run()
{
if (!headers.isEmpty())
state = State.REQUEST;
updateState(State.REQUEST);
handle();
}
});
@ -284,7 +290,7 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
@Override
public void run()
{
state = state == State.INITIAL ? State.REQUEST : State.HEADERS;
updateState(state == State.INITIAL ? State.REQUEST : State.HEADERS);
handle();
}
});
@ -292,7 +298,10 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
public void content(final DataInfo dataInfo, boolean endRequest)
{
dataInfos.offer(new ByteBufferDataInfo(dataInfo.asByteBuffer(false), dataInfo.isClose(), dataInfo.isCompress())
// We need to copy the dataInfo since we do not know when its bytes
// will be consumed. When the copy is consumed, we consume also the
// original, so the implementation can send a window update.
ByteBufferDataInfo copyDataInfo = new ByteBufferDataInfo(dataInfo.asByteBuffer(false), dataInfo.isClose(), dataInfo.isCompress())
{
@Override
public void consume(int delta)
@ -300,8 +309,11 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
super.consume(delta);
dataInfo.consume(delta);
}
});
complete = endRequest;
};
logger.debug("Queuing last={} content {}", endRequest, copyDataInfo);
dataInfos.offer(copyDataInfo);
if (endRequest)
dataInfos.offer(END_OF_CONTENT);
post(new Runnable()
{
@Override
@ -310,10 +322,10 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
logger.debug("HTTP > {} bytes of content", dataInfo.length());
if (state == State.HEADERS)
{
state = State.HEADERS_COMPLETE;
updateState(State.HEADERS_COMPLETE);
handle();
}
state = State.CONTENT;
updateState(State.CONTENT);
handle();
}
});
@ -327,10 +339,10 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
{
if (state == State.HEADERS)
{
state = State.HEADERS_COMPLETE;
updateState(State.HEADERS_COMPLETE);
handle();
}
state = State.FINAL;
updateState(State.FINAL);
handle();
}
});
@ -343,10 +355,10 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
@Override
public void run()
{
State currentState = state;
state = State.ASYNC;
State oldState = state;
updateState(State.ASYNC);
handle();
state = currentState;
updateState(oldState);
}
});
}
@ -370,12 +382,10 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
else
{
// The application has consumed the buffer, so consume also the DataInfo
if (dataInfo.consumed() == 0)
dataInfo.consume(dataInfo.length());
logger.debug("Consumed {} content bytes, queue size {}", dataInfo.consumed(), dataInfos.size());
dataInfo = null;
buffer = null;
if (complete && dataInfos.isEmpty())
return null;
// Loop to get content bytes from DataInfos
}
}
@ -388,9 +398,13 @@ public class ServerHTTPSPDYAsyncConnection extends AbstractHttpConnection implem
logger.debug("Waited {} ms for content bytes", elapsed);
if (dataInfo != null)
{
// Only consume if it's the last DataInfo
boolean consume = complete && dataInfos.isEmpty();
ByteBuffer byteBuffer = dataInfo.asByteBuffer(consume);
if (dataInfo == END_OF_CONTENT)
{
logger.debug("End of content bytes, queue size {}", dataInfos.size());
return null;
}
ByteBuffer byteBuffer = dataInfo.asByteBuffer(false);
buffer = byteBuffer.isDirect() ? new DirectNIOBuffer(byteBuffer, false) : new IndirectNIOBuffer(byteBuffer, false);
// Loop to return the buffer
}

View File

@ -33,13 +33,13 @@ import org.eclipse.jetty.spdy.api.Stream;
import org.eclipse.jetty.spdy.api.StreamFrameListener;
import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class ServerHTTPSPDYAsyncConnectionFactory extends ServerSPDYAsyncConnectionFactory
{
private static final String CONNECTION_ATTRIBUTE = "org.eclipse.jetty.spdy.http.connection";
private static final Logger logger = LoggerFactory.getLogger(ServerHTTPSPDYAsyncConnectionFactory.class);
private static final Logger logger = Log.getLogger(ServerHTTPSPDYAsyncConnectionFactory.class);
private final Connector connector;
@ -75,7 +75,7 @@ public class ServerHTTPSPDYAsyncConnectionFactory extends ServerSPDYAsyncConnect
logger.debug("Received {} on {}", synInfo, stream);
HTTPSPDYAsyncEndPoint asyncEndPoint = new HTTPSPDYAsyncEndPoint(stream);
HTTPSPDYAsyncEndPoint asyncEndPoint = new HTTPSPDYAsyncEndPoint(endPoint, stream);
ServerHTTPSPDYAsyncConnection connection = new ServerHTTPSPDYAsyncConnection(connector,
asyncEndPoint, connector.getServer(),
(SPDYAsyncConnection)endPoint.getConnection(), stream);
@ -133,10 +133,12 @@ public class ServerHTTPSPDYAsyncConnectionFactory extends ServerSPDYAsyncConnect
private class HTTPSPDYAsyncEndPoint extends EmptyAsyncEndPoint
{
private final AsyncEndPoint endPoint;
private final Stream stream;
public HTTPSPDYAsyncEndPoint(Stream stream)
private HTTPSPDYAsyncEndPoint(AsyncEndPoint endPoint, Stream stream)
{
this.endPoint = endPoint;
this.stream = stream;
}
@ -146,5 +148,41 @@ public class ServerHTTPSPDYAsyncConnectionFactory extends ServerSPDYAsyncConnect
ServerHTTPSPDYAsyncConnection connection = (ServerHTTPSPDYAsyncConnection)stream.getAttribute(CONNECTION_ATTRIBUTE);
connection.async();
}
@Override
public String getLocalAddr()
{
return endPoint.getLocalAddr();
}
@Override
public String getLocalHost()
{
return endPoint.getLocalHost();
}
@Override
public int getLocalPort()
{
return endPoint.getLocalPort();
}
@Override
public String getRemoteAddr()
{
return endPoint.getRemoteAddr();
}
@Override
public String getRemoteHost()
{
return endPoint.getRemoteHost();
}
@Override
public int getRemotePort()
{
return endPoint.getRemotePort();
}
}
}

View File

@ -190,6 +190,14 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
Assert.assertEquals("POST", httpRequest.getMethod());
Assert.assertEquals("1", httpRequest.getParameter("a"));
Assert.assertEquals("2", httpRequest.getParameter("b"));
Assert.assertNotNull(httpRequest.getRemoteHost());
Assert.assertNotNull(httpRequest.getRemotePort());
Assert.assertNotNull(httpRequest.getRemoteAddr());
Assert.assertNotNull(httpRequest.getLocalPort());
Assert.assertNotNull(httpRequest.getLocalName());
Assert.assertNotNull(httpRequest.getLocalAddr());
Assert.assertNotNull(httpRequest.getServerPort());
Assert.assertNotNull(httpRequest.getServerName());
handlerLatch.countDown();
}
}), null);
@ -519,7 +527,6 @@ public class ServerHTTPSPDYTest extends AbstractHTTPSPDYTest
@Override
public void onData(Stream stream, DataInfo dataInfo)
{
contentBytes.addAndGet(dataInfo.asByteBuffer(true).remaining());
if (dataInfo.isClose())
{

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>org.eclipse.jetty.spdy</groupId>
<artifactId>spdy-parent</artifactId>
@ -8,6 +9,7 @@
<modelVersion>4.0.0</modelVersion>
<artifactId>spdy-jetty</artifactId>
<name>Jetty :: SPDY :: Jetty Binding</name>
<build>
<plugins>
<plugin>
@ -27,7 +29,7 @@
<version>${npn.version}</version>
<type>jar</type>
<overWrite>false</overWrite>
<outputDirectory>${build.directory}/npn</outputDirectory>
<outputDirectory>${project.build.directory}/npn</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
@ -37,27 +39,12 @@
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
<argLine>-Xbootclasspath/p:${build.directory}/npn/npn-boot-${npn.version}.jar </argLine>
<argLine>-Xbootclasspath/p:${project.build.directory}/npn/npn-boot-${npn.version}.jar</argLine>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>eclipse-release</id>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty.spdy</groupId>
@ -72,7 +59,7 @@
<dependency>
<groupId>org.eclipse.jetty.npn</groupId>
<artifactId>npn-api</artifactId>
<version>${project.version}</version>
<version>${npn.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
@ -86,4 +73,5 @@
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -30,12 +30,12 @@ import org.eclipse.jetty.io.nio.NIOBuffer;
import org.eclipse.jetty.spdy.api.Handler;
import org.eclipse.jetty.spdy.api.Session;
import org.eclipse.jetty.spdy.parser.Parser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
public class SPDYAsyncConnection extends AbstractConnection implements AsyncConnection, Controller<StandardSession.FrameBytes>, IdleListener
{
private static final Logger logger = LoggerFactory.getLogger(SPDYAsyncConnection.class);
private static final Logger logger = Log.getLogger(SPDYAsyncConnection.class);
private final ByteBufferPool bufferPool;
private final Parser parser;
private volatile Session session;
@ -181,7 +181,7 @@ public class SPDYAsyncConnection extends AbstractConnection implements AsyncConn
}
catch (IOException x)
{
logger.trace("", x);
logger.ignore(x);
}
}

View File

@ -41,14 +41,14 @@ import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.spdy.api.SPDY;
import org.eclipse.jetty.spdy.api.Session;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.eclipse.jetty.util.thread.ThreadPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class SPDYServerConnector extends SelectChannelConnector
{
private static final Logger logger = LoggerFactory.getLogger(SPDYServerConnector.class);
private static final Logger logger = Log.getLogger(SPDYServerConnector.class);
// Order is important on server side, so we use a LinkedHashMap
private final Map<String, AsyncConnectionFactory> factories = new LinkedHashMap<>();

View File

@ -307,7 +307,7 @@ public class FlowControlTest extends AbstractTest
Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS));
Stream stream = session.syn(new SynInfo(true), null).get(5, TimeUnit.SECONDS);
Stream stream = session.syn(new SynInfo(false), null).get(5, TimeUnit.SECONDS);
final int length = 5 * windowSize;
stream.data(new BytesDataInfo(new byte[length], true));

View File

@ -0,0 +1,164 @@
package org.eclipse.jetty.spdy;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.spdy.api.BytesDataInfo;
import org.eclipse.jetty.spdy.api.DataInfo;
import org.eclipse.jetty.spdy.api.Headers;
import org.eclipse.jetty.spdy.api.HeadersInfo;
import org.eclipse.jetty.spdy.api.RstInfo;
import org.eclipse.jetty.spdy.api.SPDY;
import org.eclipse.jetty.spdy.api.Session;
import org.eclipse.jetty.spdy.api.SessionFrameListener;
import org.eclipse.jetty.spdy.api.SessionStatus;
import org.eclipse.jetty.spdy.api.Stream;
import org.eclipse.jetty.spdy.api.StreamFrameListener;
import org.eclipse.jetty.spdy.api.StreamStatus;
import org.eclipse.jetty.spdy.api.StringDataInfo;
import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
import org.eclipse.jetty.spdy.frames.ControlFrameType;
import org.eclipse.jetty.spdy.frames.GoAwayFrame;
import org.eclipse.jetty.spdy.frames.SynReplyFrame;
import org.eclipse.jetty.spdy.generator.Generator;
import org.junit.Assert;
import org.junit.Test;
public class ProtocolViolationsTest extends AbstractTest
{
@Test
public void testSendDataBeforeReplyIsIllegal() throws Exception
{
final CountDownLatch resetLatch = new CountDownLatch(1);
final CountDownLatch latch = new CountDownLatch(1);
Session session = startClient(startServer(new ServerSessionFrameListener.Adapter()
{
@Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{
try
{
stream.data(new StringDataInfo("failure", true));
return null;
}
catch (IllegalStateException x)
{
latch.countDown();
return null;
}
}
}), new SessionFrameListener.Adapter()
{
@Override
public void onRst(Session session, RstInfo rstInfo)
{
Assert.assertSame(StreamStatus.PROTOCOL_ERROR, rstInfo.getStreamStatus());
resetLatch.countDown();
}
});
session.syn(new SynInfo(true), null);
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
Assert.assertTrue(resetLatch.await(5, TimeUnit.SECONDS));
}
@Test
public void testReceiveDataBeforeReplyIsIllegal() throws Exception
{
ServerSocketChannel server = ServerSocketChannel.open();
server.bind(new InetSocketAddress("localhost", 0));
Session session = startClient(new InetSocketAddress("localhost", server.socket().getLocalPort()), null);
session.syn(new SynInfo(true), null);
SocketChannel channel = server.accept();
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
channel.read(readBuffer);
readBuffer.flip();
int streamId = readBuffer.getInt(8);
Generator generator = new Generator(new StandardByteBufferPool(), new StandardCompressionFactory.StandardCompressor());
byte[] bytes = new byte[1];
ByteBuffer writeBuffer = generator.data(streamId, bytes.length, new BytesDataInfo(bytes, true));
channel.write(writeBuffer);
readBuffer.clear();
channel.read(readBuffer);
readBuffer.flip();
Assert.assertEquals(ControlFrameType.RST_STREAM.getCode(), readBuffer.getShort(2));
Assert.assertEquals(streamId, readBuffer.getInt(8));
writeBuffer = generator.control(new GoAwayFrame(SPDY.V2, 0, SessionStatus.OK.getCode()));
channel.write(writeBuffer);
channel.shutdownOutput();
channel.close();
server.close();
}
@Test(expected = IllegalStateException.class)
public void testSendDataAfterCloseIsIllegal() throws Exception
{
Session session = startClient(startServer(null), null);
Stream stream = session.syn(new SynInfo(true), null).get(5, TimeUnit.SECONDS);
stream.data(new StringDataInfo("test", true));
}
@Test(expected = IllegalStateException.class)
public void testSendHeadersAfterCloseIsIllegal() throws Exception
{
Session session = startClient(startServer(null), null);
Stream stream = session.syn(new SynInfo(true), null).get(5, TimeUnit.SECONDS);
stream.headers(new HeadersInfo(new Headers(), true));
}
@Test
public void testDataSentAfterCloseIsDiscardedByRecipient() throws Exception
{
ServerSocketChannel server = ServerSocketChannel.open();
server.bind(new InetSocketAddress("localhost", 0));
Session session = startClient(new InetSocketAddress("localhost", server.socket().getLocalPort()), null);
final CountDownLatch dataLatch = new CountDownLatch(2);
session.syn(new SynInfo(true), new StreamFrameListener.Adapter()
{
@Override
public void onData(Stream stream, DataInfo dataInfo)
{
dataLatch.countDown();
}
});
SocketChannel channel = server.accept();
ByteBuffer readBuffer = ByteBuffer.allocate(1024);
channel.read(readBuffer);
readBuffer.flip();
int streamId = readBuffer.getInt(8);
Generator generator = new Generator(new StandardByteBufferPool(), new StandardCompressionFactory.StandardCompressor());
ByteBuffer writeBuffer = generator.control(new SynReplyFrame(SPDY.V2, (byte)0, streamId, new Headers()));
channel.write(writeBuffer);
byte[] bytes = new byte[1];
writeBuffer = generator.data(streamId, bytes.length, new BytesDataInfo(bytes, true));
channel.write(writeBuffer);
// Write again to simulate the faulty condition
writeBuffer.flip();
channel.write(writeBuffer);
Assert.assertFalse(dataLatch.await(1, TimeUnit.SECONDS));
writeBuffer = generator.control(new GoAwayFrame(SPDY.V2, 0, SessionStatus.OK.getCode()));
channel.write(writeBuffer);
channel.shutdownOutput();
channel.close();
server.close();
}
}

View File

@ -64,6 +64,8 @@ public class ResetStreamTest extends AbstractTest
Assert.assertEquals(0, serverSession.getStreams().size());
Assert.assertTrue(rstLatch.await(5, TimeUnit.SECONDS));
// Need to sleep a while to give the chance to the implementation to remove the stream
TimeUnit.SECONDS.sleep(1);
Assert.assertEquals(0, clientSession.getStreams().size());
}

View File

@ -87,25 +87,8 @@ public class SynDataReplyDataLoadTest extends AbstractTest
}
});
List<Callable<Object>> tasks = new ArrayList<>();
for (int i = 0; i < count; ++i)
{
tasks.add(new Callable<Object>()
{
@Override
public Object call() throws Exception
{
synCompletedData(session, headers, iterations);
return null;
}
});
}
ExecutorService threadPool = Executors.newFixedThreadPool(count);
List<Future<Object>> futures = threadPool.invokeAll(tasks);
for (Future<Object> future : futures)
future.get(iterations, TimeUnit.SECONDS);
Assert.assertTrue(latch.await(count * iterations, TimeUnit.SECONDS));
List<Callable<Object>> tasks = new ArrayList<>();
tasks.clear();
for (int i = 0; i < count; ++i)
@ -120,11 +103,38 @@ public class SynDataReplyDataLoadTest extends AbstractTest
}
});
}
futures = threadPool.invokeAll(tasks);
{
long begin = System.nanoTime();
List<Future<Object>> futures = threadPool.invokeAll(tasks);
for (Future<Object> future : futures)
future.get(iterations, TimeUnit.SECONDS);
Assert.assertTrue(latch.await(count * iterations, TimeUnit.SECONDS));
long end = System.nanoTime();
System.err.printf("SYN+GET+DATA+GET completed in %d ms%n", TimeUnit.NANOSECONDS.toMillis(end - begin));
}
tasks.clear();
for (int i = 0; i < count; ++i)
{
tasks.add(new Callable<Object>()
{
@Override
public Object call() throws Exception
{
synCompletedData(session, headers, iterations);
return null;
}
});
}
{
long begin = System.nanoTime();
List<Future<Object>> futures = threadPool.invokeAll(tasks);
for (Future<Object> future : futures)
future.get(iterations, TimeUnit.SECONDS);
Assert.assertTrue(latch.await(count * iterations, TimeUnit.SECONDS));
long end = System.nanoTime();
System.err.printf("SYN+COMPLETED+DATA completed in %d ms%n", TimeUnit.NANOSECONDS.toMillis(end - begin));
}
threadPool.shutdown();
}

View File

@ -30,12 +30,10 @@ import org.eclipse.jetty.spdy.api.DataInfo;
import org.eclipse.jetty.spdy.api.Handler;
import org.eclipse.jetty.spdy.api.Headers;
import org.eclipse.jetty.spdy.api.ReplyInfo;
import org.eclipse.jetty.spdy.api.RstInfo;
import org.eclipse.jetty.spdy.api.Session;
import org.eclipse.jetty.spdy.api.SessionFrameListener;
import org.eclipse.jetty.spdy.api.Stream;
import org.eclipse.jetty.spdy.api.StreamFrameListener;
import org.eclipse.jetty.spdy.api.StreamStatus;
import org.eclipse.jetty.spdy.api.StringDataInfo;
import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
@ -324,39 +322,6 @@ public class SynReplyTest extends AbstractTest
Assert.assertTrue(clientDataLatch.await(5, TimeUnit.SECONDS));
}
@Test
public void testSynDataRst() throws Exception
{
final AtomicReference<RstInfo> ref = new AtomicReference<>();
final CountDownLatch latch = new CountDownLatch(1);
ServerSessionFrameListener serverSessionFrameListener = new ServerSessionFrameListener.Adapter()
{
@Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{
// Do not send the reply, we expect a RST_STREAM
stream.data(new StringDataInfo("foo", true));
return null;
}
@Override
public void onRst(Session session, RstInfo rstInfo)
{
ref.set(rstInfo);
latch.countDown();
}
};
Session session = startClient(startServer(serverSessionFrameListener), null);
Stream stream = session.syn(new SynInfo(true), null).get(5, TimeUnit.SECONDS);
Assert.assertTrue(latch.await(5, TimeUnit.SECONDS));
RstInfo rstInfo = ref.get();
Assert.assertNotNull(rstInfo);
Assert.assertEquals(stream.getId(), rstInfo.getStreamId());
Assert.assertSame(StreamStatus.PROTOCOL_ERROR, rstInfo.getStreamStatus());
}
@Test
public void testSynReplyDataSynReplyData() throws Exception
{

View File

@ -287,7 +287,25 @@ public class MultiMap<K> implements ConcurrentMap<K,Object>, Serializable
*/
public Map<K,String[]> toStringArrayMap()
{
HashMap<K,String[]> map = new HashMap<K,String[]>(_map.size()*3/2);
HashMap<K,String[]> map = new HashMap<K,String[]>(_map.size()*3/2)
{
public String toString()
{
StringBuilder b=new StringBuilder();
b.append('{');
for (K k:keySet())
{
if(b.length()>1)
b.append(',');
b.append(k);
b.append('=');
b.append(Arrays.asList(get(k)));
}
b.append('}');
return b.toString();
}
};
for(Map.Entry<K,Object> entry: _map.entrySet())
{

View File

@ -14,6 +14,10 @@
package org.eclipse.jetty.util;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;
import org.eclipse.jetty.util.log.Log;
@ -67,6 +71,7 @@ public class URIUtil
*/
public static StringBuilder encodePath(StringBuilder buf, String path)
{
byte[] bytes=null;
if (buf==null)
{
loop:
@ -84,8 +89,23 @@ public class URIUtil
case '<':
case '>':
case ' ':
buf=new StringBuilder(path.length()<<1);
buf=new StringBuilder(path.length()*2);
break loop;
default:
if (c>127)
{
try
{
bytes=path.getBytes(URIUtil.__CHARSET);
}
catch (UnsupportedEncodingException e)
{
throw new IllegalStateException(e);
}
buf=new StringBuilder(path.length()*2);
break loop;
}
}
}
if (buf==null)
@ -93,6 +113,55 @@ public class URIUtil
}
synchronized(buf)
{
if (bytes!=null)
{
for (int i=0;i<bytes.length;i++)
{
byte c=bytes[i];
switch(c)
{
case '%':
buf.append("%25");
continue;
case '?':
buf.append("%3F");
continue;
case ';':
buf.append("%3B");
continue;
case '#':
buf.append("%23");
continue;
case '"':
buf.append("%22");
continue;
case '\'':
buf.append("%27");
continue;
case '<':
buf.append("%3C");
continue;
case '>':
buf.append("%3E");
continue;
case ' ':
buf.append("%20");
continue;
default:
if (c<0)
{
buf.append('%');
TypeUtil.toHex(c,buf);
}
else
buf.append((char)c);
continue;
}
}
}
else
{
for (int i=0;i<path.length();i++)
{
@ -132,6 +201,7 @@ public class URIUtil
}
}
}
}
return buf;
}

View File

@ -77,7 +77,7 @@ public class StdErrLog extends AbstractLogger
private int _level = LEVEL_INFO;
// Level that this Logger was configured as (remembered in special case of .setDebugEnabled())
private int _configuredLevel;
private PrintStream _stderr = System.err;
private PrintStream _stderr = null;
private boolean _source = __source;
// Print the long form names, otherwise use abbreviated
private boolean _printLongNames = __long;
@ -271,7 +271,7 @@ public class StdErrLog extends AbstractLogger
{
StringBuilder buffer = new StringBuilder(64);
format(buffer,":WARN:",msg,args);
_stderr.println(buffer);
(_stderr==null?System.err:_stderr).println(buffer);
}
}
@ -286,7 +286,7 @@ public class StdErrLog extends AbstractLogger
{
StringBuilder buffer = new StringBuilder(64);
format(buffer,":WARN:",msg,thrown);
_stderr.println(buffer);
(_stderr==null?System.err:_stderr).println(buffer);
}
}
@ -296,7 +296,7 @@ public class StdErrLog extends AbstractLogger
{
StringBuilder buffer = new StringBuilder(64);
format(buffer,":INFO:",msg,args);
_stderr.println(buffer);
(_stderr==null?System.err:_stderr).println(buffer);
}
}
@ -311,7 +311,7 @@ public class StdErrLog extends AbstractLogger
{
StringBuilder buffer = new StringBuilder(64);
format(buffer,":INFO:",msg,thrown);
_stderr.println(buffer);
(_stderr==null?System.err:_stderr).println(buffer);
}
}
@ -369,7 +369,7 @@ public class StdErrLog extends AbstractLogger
public void setStdErrStream(PrintStream stream)
{
this._stderr = stream;
this._stderr = stream==System.err?null:stream;
}
public void debug(String msg, Object... args)
@ -378,7 +378,7 @@ public class StdErrLog extends AbstractLogger
{
StringBuilder buffer = new StringBuilder(64);
format(buffer,":DBUG:",msg,args);
_stderr.println(buffer);
(_stderr==null?System.err:_stderr).println(buffer);
}
}
@ -393,7 +393,7 @@ public class StdErrLog extends AbstractLogger
{
StringBuilder buffer = new StringBuilder(64);
format(buffer,":DBUG:",msg,thrown);
_stderr.println(buffer);
(_stderr==null?System.err:_stderr).println(buffer);
}
}
@ -616,7 +616,7 @@ public class StdErrLog extends AbstractLogger
{
StringBuilder buffer = new StringBuilder(64);
format(buffer,":IGNORED:","",ignored);
_stderr.println(buffer);
(_stderr==null?System.err:_stderr).println(buffer);
}
}
}

View File

@ -305,7 +305,8 @@ public class WebInfConfiguration extends AbstractConfiguration
}
catch(IOException e)
{
LOG.warn("tmpdir",e); System.exit(1);
tmpDir = null;
throw new IllegalStateException("Cannot create tmp dir in "+System.getProperty("java.io.tmpdir")+ " for context "+context,e);
}
}
}

View File

@ -359,7 +359,6 @@
<module>jetty-http</module>
<module>jetty-websocket</module>
<module>jetty-continuation</module>
<module>jetty-npn</module>
<module>jetty-server</module>
<module>jetty-client</module>
<module>jetty-xml</module>