From 8ce96cdd2ea5af38300b8147457e84c3eee2f48d Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Wed, 27 Aug 2014 14:44:23 +1000 Subject: [PATCH 1/6] 441475 org.eclipse.jetty.server.ResourceCache exceptions under high load --- .../jetty/util/resource/JarResource.java | 7 +++-- .../jetty/util/resource/URLResource.java | 28 +++++++++++++++++-- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarResource.java index 3dbb70a9ffd..2f86662af66 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarResource.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/JarResource.java @@ -92,7 +92,7 @@ public class JarResource extends URLResource /* ------------------------------------------------------------ */ /** - * Returns true if the respresenetd resource exists. + * Returns true if the represented resource exists. */ @Override public boolean exists() @@ -118,7 +118,7 @@ public class JarResource extends URLResource { checkConnection(); if (!_urlString.endsWith("!/")) - return new FilterInputStream(super.getInputStream()) + return new FilterInputStream(getInputStream(false)) { @Override public void close() throws IOException {this.in=IO.getClosedStream();} @@ -129,6 +129,9 @@ public class JarResource extends URLResource return is; } + + + /* ------------------------------------------------------------ */ @Override public void copyTo(File directory) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/URLResource.java b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/URLResource.java index b696817e50b..cc302fd60b7 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/resource/URLResource.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/resource/URLResource.java @@ -197,13 +197,33 @@ public class URLResource extends Resource return _url.toExternalForm(); } + /* ------------------------------------------------------------ */ /** - * Returns an input stream to the resource + * Returns an input stream to the resource. The underlying + * url connection will be nulled out to prevent re-use. */ @Override public synchronized InputStream getInputStream() throws java.io.IOException + { + return getInputStream (true); //backwards compatibility + } + + + + /* ------------------------------------------------------------ */ + /** + * Returns an input stream to the resource, optionally nulling + * out the underlying url connection. If the connection is not + * nulled out, a subsequent call to getInputStream() may return + * an existing and already in-use input stream - this depends on + * the url protocol. Eg JarURLConnection does not reuse inputstreams. + * + * @param resetConnection if true the connection field is set to null + */ + protected synchronized InputStream getInputStream(boolean resetConnection) + throws java.io.IOException { if (!checkConnection()) throw new IOException( "Invalid resource"); @@ -220,7 +240,11 @@ public class URLResource extends Resource } finally { - _connection=null; + if (resetConnection) + { + _connection=null; + if (LOG.isDebugEnabled()) LOG.debug("Connection nulled"); + } } } From 4c8e2a6635d6a13a783a567aa890237a88a62e56 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Wed, 27 Aug 2014 16:34:24 +1000 Subject: [PATCH 2/6] 442642 Quickstart generates valid XML Fixed issues with XmlParser and WebDescriptor that were stopping validation. --- examples/quickstart/pom.xml | 12 ++ .../jetty/quickstart/PreconfigureJNDIWar.java | 2 +- .../jetty/quickstart/PreconfigureSpecWar.java | 2 +- .../PreconfigureStandardTestWar.java | 3 +- .../jetty/quickstart/QuickStartJNDIWar.java | 0 .../jetty/quickstart/QuickStartSpecWar.java | 0 .../quickstart/QuickStartStandardTestWar.java | 0 .../jetty/quickstart/QuickStartTest.java | 179 ++++++++++++++++ .../eclipse/jetty/quickstart/Quickstart.java | 0 .../src/test/resources/realm.properties | 0 .../src/test/resources/test-jndi.xml | 0 .../src/test/resources/test-spec.xml | 0 .../quickstart}/src/test/resources/test.xml | 0 .../QuickStartDescriptorGenerator.java | 195 ++++++++++-------- .../org/eclipse/jetty/webapp/Descriptor.java | 12 -- .../eclipse/jetty/webapp/WebDescriptor.java | 123 +++++------ .../java/org/eclipse/jetty/xml/XmlParser.java | 6 + 17 files changed, 377 insertions(+), 157 deletions(-) rename {jetty-quickstart => examples/quickstart}/src/test/java/org/eclipse/jetty/quickstart/PreconfigureJNDIWar.java (93%) rename {jetty-quickstart => examples/quickstart}/src/test/java/org/eclipse/jetty/quickstart/PreconfigureSpecWar.java (94%) rename {jetty-quickstart => examples/quickstart}/src/test/java/org/eclipse/jetty/quickstart/PreconfigureStandardTestWar.java (94%) rename {jetty-quickstart => examples/quickstart}/src/test/java/org/eclipse/jetty/quickstart/QuickStartJNDIWar.java (100%) rename {jetty-quickstart => examples/quickstart}/src/test/java/org/eclipse/jetty/quickstart/QuickStartSpecWar.java (100%) rename {jetty-quickstart => examples/quickstart}/src/test/java/org/eclipse/jetty/quickstart/QuickStartStandardTestWar.java (100%) create mode 100644 examples/quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartTest.java rename {jetty-quickstart => examples/quickstart}/src/test/java/org/eclipse/jetty/quickstart/Quickstart.java (100%) rename {jetty-quickstart => examples/quickstart}/src/test/resources/realm.properties (100%) rename {jetty-quickstart => examples/quickstart}/src/test/resources/test-jndi.xml (100%) rename {jetty-quickstart => examples/quickstart}/src/test/resources/test-spec.xml (100%) rename {jetty-quickstart => examples/quickstart}/src/test/resources/test.xml (100%) diff --git a/examples/quickstart/pom.xml b/examples/quickstart/pom.xml index 812b8e7b5ce..08e46952d52 100644 --- a/examples/quickstart/pom.xml +++ b/examples/quickstart/pom.xml @@ -12,6 +12,12 @@ Jetty Quick Start Example http://www.eclipse.org/jetty + + org.eclipse.jetty + jetty-quickstart + ${project.version} + test + org.eclipse.jetty jetty-webapp @@ -101,6 +107,12 @@ ${project.version} test + + org.eclipse.jetty.toolchain + jetty-test-helper + test + + diff --git a/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureJNDIWar.java b/examples/quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureJNDIWar.java similarity index 93% rename from jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureJNDIWar.java rename to examples/quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureJNDIWar.java index 570b724cae9..a8f636945ad 100644 --- a/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureJNDIWar.java +++ b/examples/quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureJNDIWar.java @@ -43,7 +43,7 @@ public class PreconfigureJNDIWar LOG.info("Preconfigured in {}ms",TimeUnit.NANOSECONDS.toMillis(System.nanoTime()-__start)); - IO.copy(new FileInputStream("target/test-jndi-preconfigured/WEB-INF/quickstart-web.xml"),System.out); + // IO.copy(new FileInputStream("target/test-jndi-preconfigured/WEB-INF/quickstart-web.xml"),System.out); } } diff --git a/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureSpecWar.java b/examples/quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureSpecWar.java similarity index 94% rename from jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureSpecWar.java rename to examples/quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureSpecWar.java index f8b49c77c2a..7dd62d83ed4 100644 --- a/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureSpecWar.java +++ b/examples/quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureSpecWar.java @@ -52,7 +52,7 @@ public class PreconfigureSpecWar LOG.info("Preconfigured in {}ms",TimeUnit.NANOSECONDS.toMillis(System.nanoTime()-__start)); - IO.copy(new FileInputStream("target/test-spec-preconfigured/WEB-INF/quickstart-web.xml"),System.out); + // IO.copy(new FileInputStream("target/test-spec-preconfigured/WEB-INF/quickstart-web.xml"),System.out); } } diff --git a/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureStandardTestWar.java b/examples/quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureStandardTestWar.java similarity index 94% rename from jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureStandardTestWar.java rename to examples/quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureStandardTestWar.java index 91e424165e1..2dcfeb7eabc 100644 --- a/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureStandardTestWar.java +++ b/examples/quickstart/src/test/java/org/eclipse/jetty/quickstart/PreconfigureStandardTestWar.java @@ -34,7 +34,6 @@ import org.eclipse.jetty.util.resource.Resource; */ public class PreconfigureStandardTestWar { - private static final long __start=System.nanoTime(); private static final Logger LOG = Log.getLogger(Server.class); @@ -57,6 +56,6 @@ public class PreconfigureStandardTestWar LOG.info("Preconfigured in {}ms",TimeUnit.NANOSECONDS.toMillis(System.nanoTime()-__start)); - IO.copy(new FileInputStream("target/test-standard-preconfigured/WEB-INF/quickstart-web.xml"),System.out); + // IO.copy(new FileInputStream("target/test-standard-preconfigured/WEB-INF/quickstart-web.xml"),System.out); } } diff --git a/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartJNDIWar.java b/examples/quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartJNDIWar.java similarity index 100% rename from jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartJNDIWar.java rename to examples/quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartJNDIWar.java diff --git a/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartSpecWar.java b/examples/quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartSpecWar.java similarity index 100% rename from jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartSpecWar.java rename to examples/quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartSpecWar.java diff --git a/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartStandardTestWar.java b/examples/quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartStandardTestWar.java similarity index 100% rename from jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartStandardTestWar.java rename to examples/quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartStandardTestWar.java diff --git a/examples/quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartTest.java b/examples/quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartTest.java new file mode 100644 index 00000000000..4ff5fff00fc --- /dev/null +++ b/examples/quickstart/src/test/java/org/eclipse/jetty/quickstart/QuickStartTest.java @@ -0,0 +1,179 @@ +// +// ======================================================================== +// Copyright (c) 1995-2014 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.quickstart; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URL; + +import org.eclipse.jetty.server.NetworkConnector; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.webapp.WebDescriptor; +import org.eclipse.jetty.xml.XmlConfiguration; +import org.eclipse.jetty.xml.XmlParser.Node; +import org.hamcrest.Matchers; +import org.junit.Test; + +public class QuickStartTest +{ + + @Test + public void testStandardTestWar() throws Exception + { + PreconfigureStandardTestWar.main(new String[]{}); + + WebDescriptor descriptor = new WebDescriptor(Resource.newResource("./target/test-standard-preconfigured/WEB-INF/quickstart-web.xml")); + descriptor.setValidating(true); + descriptor.parse(); + Node node = descriptor.getRoot(); + assertThat(node,Matchers.notNullValue()); + + System.setProperty("jetty.home", "target"); + + //war file or dir to start + String war = "target/test-standard-preconfigured"; + + //optional jetty context xml file to configure the webapp + Resource contextXml = Resource.newResource("src/test/resources/test.xml"); + + Server server = new Server(0); + + QuickStartWebApp webapp = new QuickStartWebApp(); + webapp.setAutoPreconfigure(true); + webapp.setWar(war); + webapp.setContextPath("/"); + + //apply context xml file + if (contextXml != null) + { + // System.err.println("Applying "+contextXml); + XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXml.getURL()); + xmlConfiguration.configure(webapp); + } + + server.setHandler(webapp); + + server.start(); + + URL url = new URL("http://127.0.0.1:"+server.getBean(NetworkConnector.class).getLocalPort()+"/test/dump/info"); + HttpURLConnection connection = (HttpURLConnection)url.openConnection(); + assertEquals(200,connection.getResponseCode()); + assertThat(IO.toString((InputStream)connection.getContent()),Matchers.containsString("Dump Servlet")); + + server.stop(); + } + + @Test + public void testSpecWar() throws Exception + { + PreconfigureSpecWar.main(new String[]{}); + + WebDescriptor descriptor = new WebDescriptor(Resource.newResource("./target/test-spec-preconfigured/WEB-INF/quickstart-web.xml")); + descriptor.setValidating(true); + descriptor.parse(); + Node node = descriptor.getRoot(); + assertThat(node,Matchers.notNullValue()); + + System.setProperty("jetty.home", "target"); + + //war file or dir to start + String war = "target/test-spec-preconfigured"; + + //optional jetty context xml file to configure the webapp + Resource contextXml = Resource.newResource("src/test/resources/test-spec.xml"); + + Server server = new Server(0); + + QuickStartWebApp webapp = new QuickStartWebApp(); + webapp.setAutoPreconfigure(true); + webapp.setWar(war); + webapp.setContextPath("/"); + + //apply context xml file + if (contextXml != null) + { + // System.err.println("Applying "+contextXml); + XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXml.getURL()); + xmlConfiguration.configure(webapp); + } + + server.setHandler(webapp); + + server.start(); + + URL url = new URL("http://127.0.0.1:"+server.getBean(NetworkConnector.class).getLocalPort()+"/"); + HttpURLConnection connection = (HttpURLConnection)url.openConnection(); + assertEquals(200,connection.getResponseCode()); + assertThat(IO.toString((InputStream)connection.getContent()),Matchers.containsString("Test Specification WebApp")); + + server.stop(); + } + + @Test + public void testJNDIWar() throws Exception + { + PreconfigureJNDIWar.main(new String[]{}); + + WebDescriptor descriptor = new WebDescriptor(Resource.newResource("./target/test-jndi-preconfigured/WEB-INF/quickstart-web.xml")); + descriptor.setValidating(true); + descriptor.parse(); + Node node = descriptor.getRoot(); + assertThat(node,Matchers.notNullValue()); + + System.setProperty("jetty.home", "target"); + + //war file or dir to start + String war = "target/test-jndi-preconfigured"; + + //optional jetty context xml file to configure the webapp + Resource contextXml = Resource.newResource("src/test/resources/test-jndi.xml"); + + Server server = new Server(0); + + QuickStartWebApp webapp = new QuickStartWebApp(); + webapp.setAutoPreconfigure(true); + webapp.setWar(war); + webapp.setContextPath("/"); + + //apply context xml file + if (contextXml != null) + { + // System.err.println("Applying "+contextXml); + XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXml.getURL()); + xmlConfiguration.configure(webapp); + } + + server.setHandler(webapp); + + server.start(); + + URL url = new URL("http://127.0.0.1:"+server.getBean(NetworkConnector.class).getLocalPort()+"/"); + HttpURLConnection connection = (HttpURLConnection)url.openConnection(); + assertEquals(200,connection.getResponseCode()); + String content=IO.toString((InputStream)connection.getContent()); + assertThat(content,Matchers.containsString("JNDI Test WebApp")); + + server.stop(); + } +} diff --git a/jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/Quickstart.java b/examples/quickstart/src/test/java/org/eclipse/jetty/quickstart/Quickstart.java similarity index 100% rename from jetty-quickstart/src/test/java/org/eclipse/jetty/quickstart/Quickstart.java rename to examples/quickstart/src/test/java/org/eclipse/jetty/quickstart/Quickstart.java diff --git a/jetty-quickstart/src/test/resources/realm.properties b/examples/quickstart/src/test/resources/realm.properties similarity index 100% rename from jetty-quickstart/src/test/resources/realm.properties rename to examples/quickstart/src/test/resources/realm.properties diff --git a/jetty-quickstart/src/test/resources/test-jndi.xml b/examples/quickstart/src/test/resources/test-jndi.xml similarity index 100% rename from jetty-quickstart/src/test/resources/test-jndi.xml rename to examples/quickstart/src/test/resources/test-jndi.xml diff --git a/jetty-quickstart/src/test/resources/test-spec.xml b/examples/quickstart/src/test/resources/test-spec.xml similarity index 100% rename from jetty-quickstart/src/test/resources/test-spec.xml rename to examples/quickstart/src/test/resources/test-spec.xml diff --git a/jetty-quickstart/src/test/resources/test.xml b/examples/quickstart/src/test/resources/test.xml similarity index 100% rename from jetty-quickstart/src/test/resources/test.xml rename to examples/quickstart/src/test/resources/test.xml diff --git a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorGenerator.java b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorGenerator.java index 5a56625fb00..b881a856068 100644 --- a/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorGenerator.java +++ b/jetty-quickstart/src/main/java/org/eclipse/jetty/quickstart/QuickStartDescriptorGenerator.java @@ -19,9 +19,7 @@ package org.eclipse.jetty.quickstart; -import java.io.File; import java.io.FileNotFoundException; -import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.util.Collection; @@ -50,7 +48,6 @@ import org.eclipse.jetty.security.authentication.FormAuthenticator; import org.eclipse.jetty.servlet.ErrorPageErrorHandler; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.FilterMapping; -import org.eclipse.jetty.servlet.Holder; import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletMapping; @@ -129,7 +126,7 @@ public class QuickStartDescriptorGenerator out.openTag("web-app",webappAttr); if (_webApp.getDisplayName() != null) out.tag("display-name",_webApp.getDisplayName()); - + // Set some special context parameters // The location of the war file on disk @@ -163,7 +160,7 @@ public class QuickStartDescriptorGenerator if (servlets.getFilters() != null) { for (FilterHolder holder : servlets.getFilters()) - outholder(out,md,"filter",holder); + outholder(out,md,holder); } if (servlets.getFilterMappings() != null) @@ -199,7 +196,7 @@ public class QuickStartDescriptorGenerator if (servlets.getServlets() != null) { for (ServletHolder holder : servlets.getServlets()) - outholder(out,md,"servlet",holder); + outholder(out,md,holder); } if (servlets.getServletMappings() != null) @@ -250,16 +247,37 @@ public class QuickStartDescriptorGenerator { out.openTag("security-constraint"); - if (m.getConstraint().getAuthenticate()) + out.openTag("web-resource-collection"); { - out.openTag("auth-constraint"); - if (m.getConstraint().getRoles()!=null) - for (String r : m.getConstraint().getRoles()) - out.tag("role-name",r); + if (m.getConstraint().getName()!=null) + out.tag("web-resource-name",m.getConstraint().getName()); + if (m.getPathSpec()!=null) + out.tag("url-pattern",origin(md,"constraint.url."+m.getPathSpec()),m.getPathSpec()); + if (m.getMethod()!=null) + out.tag("http-method",m.getMethod()); + + if (m.getMethodOmissions()!=null) + for (String o:m.getMethodOmissions()) + out.tag("http-method-omission",o); out.closeTag(); } + if (m.getConstraint().getAuthenticate()) + { + String[] roles = m.getConstraint().getRoles(); + if (roles!=null && roles.length>0) + { + out.openTag("auth-constraint"); + if (m.getConstraint().getRoles()!=null) + for (String r : m.getConstraint().getRoles()) + out.tag("role-name",r); + out.closeTag(); + } + else + out.tag("auth-constraint"); + } + switch (m.getConstraint().getDataConstraint()) { case Constraint.DC_NONE: @@ -279,22 +297,6 @@ public class QuickStartDescriptorGenerator } - out.openTag("web-resource-collection"); - { - if (m.getConstraint().getName()!=null) - out.tag("web-resource-name",m.getConstraint().getName()); - if (m.getPathSpec()!=null) - out.tag("url-pattern",origin(md,"constraint.url."+m.getPathSpec()),m.getPathSpec()); - if (m.getMethod()!=null) - out.tag("http-method",m.getMethod()); - - if (m.getMethodOmissions()!=null) - for (String o:m.getMethodOmissions()) - out.tag("http-method-omission",o); - - out.closeTag(); - } - out.closeTag(); } @@ -331,12 +333,6 @@ public class QuickStartDescriptorGenerator int maxInactiveSec = _webApp.getSessionHandler().getSessionManager().getMaxInactiveInterval(); out.tag("session-timeout", (maxInactiveSec==0?"0":Integer.toString(maxInactiveSec/60))); - Set modes =_webApp. getSessionHandler().getSessionManager().getEffectiveSessionTrackingModes(); - if (modes != null) - { - for (SessionTrackingMode mode:modes) - out.tag("tracking-mode", mode.toString()); - } //cookie-config SessionCookieConfig cookieConfig = _webApp.getSessionHandler().getSessionManager().getSessionCookieConfig(); @@ -360,6 +356,15 @@ public class QuickStartDescriptorGenerator out.tag("max-age", origin(md, "cookie-config.max-age"), Integer.toString(cookieConfig.getMaxAge())); out.closeTag(); } + + // tracking-modes + Set modes =_webApp. getSessionHandler().getSessionManager().getEffectiveSessionTrackingModes(); + if (modes != null) + { + for (SessionTrackingMode mode:modes) + out.tag("tracking-mode", mode.toString()); + } + out.closeTag(); } @@ -560,29 +565,57 @@ public class QuickStartDescriptorGenerator * @param holder * @throws IOException */ - private void outholder(XmlAppendable out, MetaData md, String tag, Holder holder) throws IOException + private void outholder(XmlAppendable out, MetaData md, FilterHolder holder) throws IOException { - out.openTag(tag,Collections.singletonMap("source",holder.getSource().toString())); + if (LOG.isDebugEnabled()) + out.openTag("filter",Collections.singletonMap("source",holder.getSource().toString())); + else + out.openTag("filter"); + String n = holder.getName(); - out.tag(tag + "-name",n); + out.tag("filter-name",n); - String ot = n + "." + tag + "."; + String ot = n + ".filter."; if (holder instanceof FilterHolder) - out.tag(tag + "-class",origin(md,ot + tag + "-class"),holder.getClassName()); - else if (holder instanceof ServletHolder) { - ServletHolder s = (ServletHolder)holder; - if (s.getForcedPath() != null && s.getClassName() == null) - out.tag("jsp-file",s.getForcedPath()); - else - out.tag(tag + "-class",origin(md,ot + tag + "-class"),s.getClassName()); - + out.tag("filter-class",origin(md,ot + "filter-class"),holder.getClassName()); + out.tag("async-supported",origin(md,ot + "async-supported"),holder.isAsyncSupported()?"true":"false"); } + + for (String p : holder.getInitParameters().keySet()) + { + out.openTag("init-param",origin(md,ot + "init-param." + p)) + .tag("param-name",p) + .tag("param-value",holder.getInitParameter(p)) + .closeTag(); + } + + out.closeTag(); + } + + private void outholder(XmlAppendable out, MetaData md, ServletHolder holder) throws IOException + { + + if (LOG.isDebugEnabled()) + out.openTag("servlet",Collections.singletonMap("source",holder.getSource().toString())); + else + out.openTag("servlet"); + + String n = holder.getName(); + out.tag("servlet-name",n); + + String ot = n + ".servlet."; + + ServletHolder s = (ServletHolder)holder; + if (s.getForcedPath() != null && s.getClassName() == null) + out.tag("jsp-file",s.getForcedPath()); + else + out.tag("servlet-class",origin(md,ot + "servlet-class"),s.getClassName()); for (String p : holder.getInitParameters().keySet()) { - if ("scratchdir".equalsIgnoreCase(p)) //don't preconfigure the temp dir for jsp output + if ("jsp".equalsIgnoreCase(n) && "scratchdir".equalsIgnoreCase(p)) //don't preconfigure the temp dir for jsp output continue; out.openTag("init-param",origin(md,ot + "init-param." + p)) .tag("param-name",p) @@ -590,50 +623,46 @@ public class QuickStartDescriptorGenerator .closeTag(); } - if (holder instanceof ServletHolder) + if (s.getInitOrder() >= 0) + out.tag("load-on-startup",Integer.toString(s.getInitOrder())); + + if (!s.isEnabled()) + out.tag("enabled",origin(md,ot + "enabled"),"false"); + + out.tag("async-supported",origin(md,ot + "async-supported"),holder.isAsyncSupported()?"true":"false"); + + if (s.getRunAsRole() != null) + out.openTag("run-as",origin(md,ot + "run-as")) + .tag("role-name",s.getRunAsRole()) + .closeTag(); + + Map roles = s.getRoleRefMap(); + if (roles!=null) { - ServletHolder s = (ServletHolder)holder; - if (s.getInitOrder() >= 0) - out.tag("load-on-startup",Integer.toString(s.getInitOrder())); - - if (s.getRunAsRole() != null) - out.openTag("run-as",origin(md,ot + "run-as")) - .tag("role-name",s.getRunAsRole()) + for (Map.Entry e : roles.entrySet()) + { + out.openTag("security-role-ref",origin(md,ot+"role-name."+e.getKey())) + .tag("role-name",e.getKey()) + .tag("role-link",e.getValue()) .closeTag(); - - Map roles = s.getRoleRefMap(); - if (roles!=null) - { - for (Map.Entry e : roles.entrySet()) - { - out.openTag("security-role-ref",origin(md,ot+"role-name."+e.getKey())) - .tag("role-name",e.getKey()) - .tag("role-link",e.getValue()) - .closeTag(); - } - } - - if (!s.isEnabled()) - out.tag("enabled",origin(md,ot + "enabled"),"false"); - - //multipart-config - MultipartConfigElement multipartConfig = ((ServletHolder.Registration)s.getRegistration()).getMultipartConfig(); - if (multipartConfig != null) - { - out.openTag("multipart-config", origin(md, s.getName()+".servlet.multipart-config")); - if (multipartConfig.getLocation() != null) - out.tag("location", multipartConfig.getLocation()); - out.tag("max-file-size", Long.toString(multipartConfig.getMaxFileSize())); - out.tag("max-request-size", Long.toString(multipartConfig.getMaxRequestSize())); - out.tag("file-size-threshold", Long.toString(multipartConfig.getFileSizeThreshold())); - out.closeTag(); } } - out.tag("async-supported",origin(md,ot + "async-supported"),holder.isAsyncSupported()?"true":"false"); + //multipart-config + MultipartConfigElement multipartConfig = ((ServletHolder.Registration)s.getRegistration()).getMultipartConfig(); + if (multipartConfig != null) + { + out.openTag("multipart-config", origin(md, s.getName()+".servlet.multipart-config")); + if (multipartConfig.getLocation() != null) + out.tag("location", multipartConfig.getLocation()); + out.tag("max-file-size", Long.toString(multipartConfig.getMaxFileSize())); + out.tag("max-request-size", Long.toString(multipartConfig.getMaxRequestSize())); + out.tag("file-size-threshold", Long.toString(multipartConfig.getFileSizeThreshold())); + out.closeTag(); + } + out.closeTag(); } - /** diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Descriptor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Descriptor.java index cec0e58840a..a228fa90f15 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Descriptor.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Descriptor.java @@ -18,8 +18,6 @@ package org.eclipse.jetty.webapp; -import java.net.URL; - import org.eclipse.jetty.util.resource.Resource; import org.eclipse.jetty.xml.XmlParser; @@ -35,19 +33,9 @@ public abstract class Descriptor _xml = xml; } - public abstract XmlParser newParser() - throws ClassNotFoundException; - public abstract void ensureParser() throws ClassNotFoundException; - protected void redirect(XmlParser parser, String resource, URL source) - { - if (source != null) - parser.redirectEntity(resource, source); - } - - public void setValidating (boolean validating) { _validating = validating; diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebDescriptor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebDescriptor.java index cef576a7716..487002f1454 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebDescriptor.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebDescriptor.java @@ -54,20 +54,23 @@ public class WebDescriptor extends Descriptor protected List _ordering = new ArrayList(); @Override - public void ensureParser() - throws ClassNotFoundException + public void ensureParser() throws ClassNotFoundException { - if (_parserSingleton == null) + synchronized (WebDescriptor.class) { - _parserSingleton = newParser(); + if (_parserSingleton == null) + _parserSingleton = newParser(isValidating()); } - _parser = _parserSingleton; + + if (_parserSingleton.isValidating()==isValidating()) + _parser = _parserSingleton; + else + _parser = newParser(isValidating()); } - public XmlParser newParser() - throws ClassNotFoundException + public static XmlParser newParser(boolean validating) throws ClassNotFoundException { - XmlParser xmlParser=new XmlParser() + XmlParser xmlParser=new XmlParser(validating) { boolean mapped=false; @@ -136,56 +139,56 @@ public class WebDescriptor extends Descriptor if (jsp22xsd == null) jsp22xsd = Loader.getResource(Servlet.class, "javax/servlet/jsp/resources/jsp_2_2.xsd"); if (jsp23xsd == null) jsp23xsd = Loader.getResource(Servlet.class, "javax/servlet/jsp/resources/jsp_2_3.xsd"); } - - redirect(this,"web-app_2_2.dtd",dtd22); - redirect(this,"-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN",dtd22); - redirect(this,"web.dtd",dtd23); - redirect(this,"web-app_2_3.dtd",dtd23); - redirect(this,"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",dtd23); - redirect(this,"XMLSchema.dtd",schemadtd); - redirect(this,"http://www.w3.org/2001/XMLSchema.dtd",schemadtd); - redirect(this,"-//W3C//DTD XMLSCHEMA 200102//EN",schemadtd); - redirect(this,"jsp_2_0.xsd",jsp20xsd); - redirect(this,"http://java.sun.com/xml/ns/j2ee/jsp_2_0.xsd",jsp20xsd); - redirect(this,"http://java.sun.com/xml/ns/javaee/jsp_2_1.xsd",jsp21xsd); - redirect(this,"jsp_2_2.xsd",jsp22xsd); - redirect(this,"http://java.sun.com/xml/ns/javaee/jsp_2_2.xsd",jsp22xsd); - redirect(this,"jsp_2_3.xsd",jsp23xsd); - redirect(this,"http://xmlns.jcp.org/xml/ns/javaee/jsp_2_3.xsd",jsp23xsd); - redirect(this,"j2ee_1_4.xsd",j2ee14xsd); - redirect(this,"http://java.sun.com/xml/ns/j2ee/j2ee_1_4.xsd",j2ee14xsd); - redirect(this, "http://java.sun.com/xml/ns/javaee/javaee_5.xsd",javaee5); - redirect(this, "http://java.sun.com/xml/ns/javaee/javaee_6.xsd",javaee6); - redirect(this, "http://xmlns.jcp.org/xml/ns/javaee/javaee_7.xsd",javaee7); - redirect(this,"web-app_2_4.xsd",webapp24xsd); - redirect(this,"http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd",webapp24xsd); - redirect(this,"web-app_2_5.xsd",webapp25xsd); - redirect(this,"http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd",webapp25xsd); - redirect(this,"web-app_3_0.xsd",webapp30xsd); - redirect(this,"http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd",webapp30xsd); - redirect(this,"web-common_3_0.xsd",webcommon30xsd); - redirect(this,"http://java.sun.com/xml/ns/javaee/web-common_3_0.xsd",webcommon30xsd); - redirect(this,"web-fragment_3_0.xsd",webfragment30xsd); - redirect(this,"http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd",webfragment30xsd); - redirect(this,"web-app_3_1.xsd",webapp31xsd); - redirect(this,"http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd",webapp31xsd); - redirect(this,"web-common_3_1.xsd",webcommon30xsd); - redirect(this,"http://xmlns.jcp.org/xml/ns/javaee/web-common_3_1.xsd",webcommon31xsd); - redirect(this,"web-fragment_3_1.xsd",webfragment30xsd); - redirect(this,"http://xmlns.jcp.org/xml/ns/javaee/web-fragment_3_1.xsd",webfragment31xsd); - redirect(this,"xml.xsd",xmlxsd); - redirect(this,"http://www.w3.org/2001/xml.xsd",xmlxsd); - redirect(this,"datatypes.dtd",datatypesdtd); - redirect(this,"http://www.w3.org/2001/datatypes.dtd",datatypesdtd); - redirect(this,"j2ee_web_services_client_1_1.xsd",webservice11xsd); - redirect(this,"http://www.ibm.com/webservices/xsd/j2ee_web_services_client_1_1.xsd",webservice11xsd); - redirect(this,"javaee_web_services_client_1_2.xsd",webservice12xsd); - redirect(this,"http://www.ibm.com/webservices/xsd/javaee_web_services_client_1_2.xsd",webservice12xsd); - redirect(this,"javaee_web_services_client_1_3.xsd",webservice13xsd); - redirect(this,"http://java.sun.com/xml/ns/javaee/javaee_web_services_client_1_3.xsd",webservice13xsd); - redirect(this,"javaee_web_services_client_1_4.xsd",webservice14xsd); - redirect(this,"http://xmlns.jcp.org/xml/ns/javaee/javaee_web_services_client_1_4.xsd",webservice14xsd); + redirectEntity("web-app_2_2.dtd",dtd22); + redirectEntity("-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN",dtd22); + redirectEntity("web.dtd",dtd23); + redirectEntity("web-app_2_3.dtd",dtd23); + redirectEntity("-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN",dtd23); + redirectEntity("XMLSchema.dtd",schemadtd); + redirectEntity("http://www.w3.org/2001/XMLSchema.dtd",schemadtd); + redirectEntity("-//W3C//DTD XMLSCHEMA 200102//EN",schemadtd); + redirectEntity("jsp_2_0.xsd",jsp20xsd); + redirectEntity("http://java.sun.com/xml/ns/j2ee/jsp_2_0.xsd",jsp20xsd); + redirectEntity("http://java.sun.com/xml/ns/javaee/jsp_2_1.xsd",jsp21xsd); + redirectEntity("jsp_2_2.xsd",jsp22xsd); + redirectEntity("http://java.sun.com/xml/ns/javaee/jsp_2_2.xsd",jsp22xsd); + redirectEntity("jsp_2_3.xsd",jsp23xsd); + redirectEntity("http://xmlns.jcp.org/xml/ns/javaee/jsp_2_3.xsd",jsp23xsd); + redirectEntity("j2ee_1_4.xsd",j2ee14xsd); + redirectEntity("http://java.sun.com/xml/ns/j2ee/j2ee_1_4.xsd",j2ee14xsd); + redirectEntity( "http://java.sun.com/xml/ns/javaee/javaee_5.xsd",javaee5); + redirectEntity( "http://java.sun.com/xml/ns/javaee/javaee_6.xsd",javaee6); + redirectEntity( "http://xmlns.jcp.org/xml/ns/javaee/javaee_7.xsd",javaee7); + redirectEntity("web-app_2_4.xsd",webapp24xsd); + redirectEntity("http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd",webapp24xsd); + redirectEntity("web-app_2_5.xsd",webapp25xsd); + redirectEntity("http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd",webapp25xsd); + redirectEntity("web-app_3_0.xsd",webapp30xsd); + redirectEntity("http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd",webapp30xsd); + redirectEntity("web-common_3_0.xsd",webcommon30xsd); + redirectEntity("http://java.sun.com/xml/ns/javaee/web-common_3_0.xsd",webcommon30xsd); + redirectEntity("web-fragment_3_0.xsd",webfragment30xsd); + redirectEntity("http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd",webfragment30xsd); + redirectEntity("web-app_3_1.xsd",webapp31xsd); + redirectEntity("http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd",webapp31xsd); + + redirectEntity("web-common_3_1.xsd",webcommon30xsd); + redirectEntity("http://xmlns.jcp.org/xml/ns/javaee/web-common_3_1.xsd",webcommon31xsd); + redirectEntity("web-fragment_3_1.xsd",webfragment30xsd); + redirectEntity("http://xmlns.jcp.org/xml/ns/javaee/web-fragment_3_1.xsd",webfragment31xsd); + redirectEntity("xml.xsd",xmlxsd); + redirectEntity("http://www.w3.org/2001/xml.xsd",xmlxsd); + redirectEntity("datatypes.dtd",datatypesdtd); + redirectEntity("http://www.w3.org/2001/datatypes.dtd",datatypesdtd); + redirectEntity("j2ee_web_services_client_1_1.xsd",webservice11xsd); + redirectEntity("http://www.ibm.com/webservices/xsd/j2ee_web_services_client_1_1.xsd",webservice11xsd); + redirectEntity("javaee_web_services_client_1_2.xsd",webservice12xsd); + redirectEntity("http://www.ibm.com/webservices/xsd/javaee_web_services_client_1_2.xsd",webservice12xsd); + redirectEntity("javaee_web_services_client_1_3.xsd",webservice13xsd); + redirectEntity("http://java.sun.com/xml/ns/javaee/javaee_web_services_client_1_3.xsd",webservice13xsd); + redirectEntity("javaee_web_services_client_1_4.xsd",webservice14xsd); + redirectEntity("http://xmlns.jcp.org/xml/ns/javaee/javaee_web_services_client_1_4.xsd",webservice14xsd); } }; @@ -316,7 +319,11 @@ public class WebDescriptor extends Descriptor { _validating = validating; } - + + public boolean isValidating () + { + return _validating; + } public boolean isOrdered() { diff --git a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlParser.java b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlParser.java index 31ef0afc39e..a5e91615a3a 100644 --- a/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlParser.java +++ b/jetty-xml/src/main/java/org/eclipse/jetty/xml/XmlParser.java @@ -132,6 +132,12 @@ public class XmlParser } } + /* ------------------------------------------------------------ */ + public boolean isValidating() + { + return _parser.isValidating(); + } + /* ------------------------------------------------------------ */ /** * @param name From 0aeebc4ec060ff188207fa18d57d2b4a2ce2431a Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Wed, 27 Aug 2014 17:11:59 +1000 Subject: [PATCH 3/6] 435988 ContainerLifeCycle: beans never stopped on remove --- .../eclipse/jetty/util/component/ContainerLifeCycle.java | 3 ++- .../jetty/util/component/ContainerLifeCycleTest.java | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java index 28c45664bf7..d8ff0e27e71 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java @@ -524,6 +524,7 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container, { if (_beans.remove(bean)) { + boolean wasManaged = bean.isManaged(); unmanage(bean); @@ -534,7 +535,7 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container, removeEventListener((Container.Listener)bean._bean); // stop managed beans - if (bean._managed==Managed.MANAGED && bean._bean instanceof LifeCycle) + if (wasManaged && bean._bean instanceof LifeCycle) { try { diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/component/ContainerLifeCycleTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/component/ContainerLifeCycleTest.java index ddc152be381..37c4c8a6813 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/component/ContainerLifeCycleTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/component/ContainerLifeCycleTest.java @@ -123,10 +123,14 @@ public class ContainerLifeCycleTest Assert.assertEquals(1,destroyed.get()); a0.removeBean(a1); + Assert.assertEquals(3,started.get()); + Assert.assertEquals(3,stopped.get()); + Assert.assertEquals(1,destroyed.get()); + a0.stop(); a0.destroy(); Assert.assertEquals(3,started.get()); - Assert.assertEquals(2,stopped.get()); + Assert.assertEquals(3,stopped.get()); Assert.assertEquals(1,destroyed.get()); a1.stop(); From 8f62be9fefc12ff8f43b57c3b235af70e326e479 Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Wed, 27 Aug 2014 17:22:37 +1000 Subject: [PATCH 4/6] 442628 Update example xml file for second server instance to extract wars --- examples/embedded/src/main/resources/jetty-otherserver.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/embedded/src/main/resources/jetty-otherserver.xml b/examples/embedded/src/main/resources/jetty-otherserver.xml index 04e3358bbb3..4c8a5cd7784 100644 --- a/examples/embedded/src/main/resources/jetty-otherserver.xml +++ b/examples/embedded/src/main/resources/jetty-otherserver.xml @@ -36,8 +36,9 @@ - /other-webapps + /other-webapps /etc/webdefault.xml + true From 21d590a74a34c9eb9a9f4ce92b3dbfd8918065bd Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Thu, 28 Aug 2014 16:52:26 +1000 Subject: [PATCH 5/6] 442759 Allow specific ServletContainerInitializers to be excluded --- .../annotations/AnnotationConfiguration.java | 150 ++++++++++++------ 1 file changed, 101 insertions(+), 49 deletions(-) diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java index 8b8d7e28df1..cf340b8ccac 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java @@ -36,6 +36,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; + import javax.servlet.ServletContainerInitializer; import javax.servlet.annotation.HandlesTypes; @@ -62,6 +64,7 @@ public class AnnotationConfiguration extends AbstractConfiguration { private static final Logger LOG = Log.getLogger(AnnotationConfiguration.class); + public static final String SERVLET_CONTAINER_INITIALIZER_EXCLUSION_PATTERN = "org.eclipse.jetty.containerInitializerExclusionPattern"; public static final String SERVLET_CONTAINER_INITIALIZER_ORDER = "org.eclipse.jetty.containerInitializerOrder"; public static final String CLASS_INHERITANCE_MAP = "org.eclipse.jetty.classInheritanceMap"; public static final String CONTAINER_INITIALIZERS = "org.eclipse.jetty.containerInitializers"; @@ -83,6 +86,7 @@ public class AnnotationConfiguration extends AbstractConfiguration protected CounterStatistic _containerPathStats; protected CounterStatistic _webInfLibStats; protected CounterStatistic _webInfClassesStats; + protected Pattern _sciExcludePattern; /** * TimeStatistic @@ -390,6 +394,8 @@ public class AnnotationConfiguration extends AbstractConfiguration { _webAppClassNameResolver = new WebAppClassNameResolver(context); _containerClassNameResolver = new ContainerClassNameResolver(context); + String tmp = (String)context.getAttribute(SERVLET_CONTAINER_INITIALIZER_EXCLUSION_PATTERN); + _sciExcludePattern = (tmp==null?null:Pattern.compile(tmp)); } @@ -747,9 +753,11 @@ public class AnnotationConfiguration extends AbstractConfiguration if (context == null) throw new IllegalArgumentException("WebAppContext null"); + if (LOG.isDebugEnabled()) LOG.debug("Checking {} for jar exclusion", sci); + //A ServletContainerInitializer that came from the container's classpath cannot be excluded by an ordering //of WEB-INF/lib jars - if (sci.getClass().getClassLoader()==context.getClassLoader().getParent()) + if (isFromContainerClassPath(context, sci)) return false; List orderedJars = context.getMetaData().getOrderedWebInfJars(); @@ -778,6 +786,38 @@ public class AnnotationConfiguration extends AbstractConfiguration } + /** + * Test if the ServletContainerIntializer is excluded by the + * o.e.j.containerInitializerExclusionPattern + * @param context + * @param sci + * @return + */ + public boolean matchesExclusionPattern(ServletContainerInitializer sci) + { + //no exclusion pattern, no SCI is excluded by it + if (_sciExcludePattern == null) + return false; + + //test if name of class matches the regex + if (LOG.isDebugEnabled()) LOG.debug("Checking {} against containerInitializerExclusionPattern",sci.getClass().getName()); + return _sciExcludePattern.matcher(sci.getClass().getName()).matches(); + } + + + /** + * Test if the ServletContainerInitializer is from the container classpath + * + * @param context + * @param sci + * @return + */ + public boolean isFromContainerClassPath (WebAppContext context, ServletContainerInitializer sci) + { + if (sci == null) + return false; + return sci.getClass().getClassLoader()==context.getClassLoader().getParent(); + } /** * @param context @@ -809,73 +849,79 @@ public class AnnotationConfiguration extends AbstractConfiguration if (LOG.isDebugEnabled()) LOG.debug("Service loaders found in {}ms", (TimeUnit.MILLISECONDS.convert((System.nanoTime()-start), TimeUnit.NANOSECONDS))); - + + + Map sciResourceMap = new HashMap(); ServletContainerInitializerOrdering initializerOrdering = getInitializerOrdering(context); - + + //Get initial set of SCIs that aren't from excluded jars or excluded by the containerExclusionPattern, or excluded + //because containerInitializerOrdering omits it + for (ServletContainerInitializer sci:loadedInitializers) + { + if (matchesExclusionPattern(sci)) + { + if (LOG.isDebugEnabled()) LOG.debug("{} excluded by pattern", sci); + continue; + } + + Resource sciResource = getJarFor(sci); + if (isFromExcludedJar(context, sci, sciResource)) + { + if (LOG.isDebugEnabled()) LOG.debug("{} is from excluded jar", sci); + continue; + } + + //check containerInitializerOrdering doesn't exclude it + String name = sci.getClass().getName(); + if (initializerOrdering != null + && (!initializerOrdering.hasWildcard() && initializerOrdering.getIndexOf(name) < 0)) + { + if (LOG.isDebugEnabled()) LOG.debug("{} is excluded by ordering", sci); + continue; + } + + sciResourceMap.put(sci, sciResource); + } + + //Order the SCIs that are included if (initializerOrdering != null && !initializerOrdering.isDefaultOrder()) { if (LOG.isDebugEnabled()) LOG.debug("Ordering ServletContainerInitializers with "+initializerOrdering); - + //There is an ordering that is not just "*". //Arrange ServletContainerInitializers according to the ordering of classnames given, irrespective of coming from container or webapp classpaths - for (ServletContainerInitializer sci:loadedInitializers) - { - Resource sciResource = getJarFor(sci); - if (!isFromExcludedJar(context, sci, sciResource)) - { - String name = sci.getClass().getName(); - if (initializerOrdering.getIndexOf(name) >= 0 || initializerOrdering.hasWildcard()) - nonExcludedInitializers.add(sci); - } - } - - //apply the ordering + nonExcludedInitializers.addAll(sciResourceMap.keySet()); Collections.sort(nonExcludedInitializers, new ServletContainerInitializerComparator(initializerOrdering)); } else { - //No ordering specified, or just the wildcard value "*" specified. + //No jetty-specific ordering specified, or just the wildcard value "*" specified. //Fallback to ordering the ServletContainerInitializers according to: - //container classpath first, WEB-INF/clases then WEB-INF/lib (obeying any web.xml jar ordering) - if (LOG.isDebugEnabled()) - LOG.debug("Ordering ServletContainerInitializers as container path, webapp path"); - - Map webappPathInitializerResourceMap = new HashMap(); - for (ServletContainerInitializer sci : loadedInitializers) - { - //if its on the container's classpath then add it - if (sci.getClass().getClassLoader() == context.getClassLoader().getParent()) - { - nonExcludedInitializers.add(sci); - } - else - { - //if on the webapp's classpath then check the containing jar is not excluded from consideration - Resource sciResource = getJarFor(sci); - if (!isFromExcludedJar(context, sci, sciResource)) - { - webappPathInitializerResourceMap.put(sci, sciResource); - } - } - } - - //add the webapp classpath ones according to any web.xml ordering + //container classpath first, WEB-INF/classes then WEB-INF/lib (obeying any web.xml jar ordering) + + //no web.xml ordering defined, add SCIs in any order if (context.getMetaData().getOrdering() == null) - nonExcludedInitializers.addAll(webappPathInitializerResourceMap.keySet()); //no ordering, just add them + { + if (LOG.isDebugEnabled()) LOG.debug("No web.xml ordering, ServletContainerInitializers in random order"); + nonExcludedInitializers.addAll(sciResourceMap.keySet()); + } else { - //add in any ServletContainerInitializers which are not in a jar, as they must be from WEB-INF/classes - for (Map.Entry entry:webappPathInitializerResourceMap.entrySet()) + if (LOG.isDebugEnabled()) LOG.debug("Ordering ServletContainerInitializers with ordering {}",context.getMetaData().getOrdering()); + for (Map.Entry entry:sciResourceMap.entrySet()) { - if (entry.getValue() == null) + //add in SCIs from the container classpath + if (entry.getKey().getClass().getClassLoader()==context.getClassLoader().getParent()) + nonExcludedInitializers.add(entry.getKey()); + else if (entry.getValue() == null) //add in SCIs not in a jar, as they must be from WEB-INF/classes and can't be ordered nonExcludedInitializers.add(entry.getKey()); } - - //add ServletContainerInitializers according to the ordering of its containing jar + + //add SCIs according to the ordering of its containing jar for (Resource webInfJar:context.getMetaData().getOrderedWebInfJars()) { - for (Map.Entry entry:webappPathInitializerResourceMap.entrySet()) + for (Map.Entry entry:sciResourceMap.entrySet()) { if (webInfJar.equals(entry.getValue())) nonExcludedInitializers.add(entry.getKey()); @@ -883,7 +929,13 @@ public class AnnotationConfiguration extends AbstractConfiguration } } } - + + if (LOG.isDebugEnabled()) + { + int i=0; + for (ServletContainerInitializer sci:nonExcludedInitializers) + LOG.debug("ServletContainerInitializer: {} {}",(++i), sci.getClass().getName()); + } return nonExcludedInitializers; } From eee2ba206e219a289b8a17e8ef663d7b63e4e4c4 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Fri, 29 Aug 2014 11:55:06 +1000 Subject: [PATCH 6/6] 435322 Added a idleTimeout to the SharedBlockerCallback --- .../org/eclipse/jetty/server/HttpChannel.java | 20 +++++++ .../org/eclipse/jetty/server/HttpOutput.java | 9 ++- .../eclipse/jetty/server/HttpTransport.java | 2 +- .../server/handler/IdleTimeoutHandler.java | 24 +++----- .../jetty/util/SharedBlockingCallback.java | 56 ++++++++++++++----- .../common/BlockingWriteCallback.java | 40 +++++++++++-- 6 files changed, 113 insertions(+), 38 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java index ee99477ef8f..530776971b3 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannel.java @@ -149,6 +149,26 @@ public class HttpChannel implements HttpParser.RequestHandler, Runnable, H { return _transport; } + + /** + * Get the idle timeout. + *

This is implemented as a call to {@link EndPoint#getIdleTimeout()}, but may be + * overridden by channels that have timeouts different from their connections. + */ + public long getIdleTimeout() + { + return _endPoint.getIdleTimeout(); + } + + /** + * Set the idle timeout. + *

This is implemented as a call to {@link EndPoint#setIdleTimeout(long), but may be + * overridden by channels that have timeouts different from their connections. + */ + public void setIdleTimeout(long timeoutMs) + { + _endPoint.setIdleTimeout(timeoutMs); + } public ByteBufferPool getByteBufferPool() { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java index d7cea8b4e5f..122f2935295 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpOutput.java @@ -52,7 +52,14 @@ public class HttpOutput extends ServletOutputStream implements Runnable { private static Logger LOG = Log.getLogger(HttpOutput.class); private final HttpChannel _channel; - private final SharedBlockingCallback _writeblock=new SharedBlockingCallback(); + private final SharedBlockingCallback _writeblock=new SharedBlockingCallback() + { + @Override + protected long getIdleTimeout() + { + return _channel.getIdleTimeout(); + } + }; private long _written; private ByteBuffer _aggregate; private int _bufferSize; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java index 7058425f659..1a1f5a78eb2 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpTransport.java @@ -24,7 +24,7 @@ import org.eclipse.jetty.http.HttpGenerator; import org.eclipse.jetty.util.Callback; public interface HttpTransport -{ +{ void send(HttpGenerator.ResponseInfo info, ByteBuffer content, boolean lastContent, Callback callback); void send(ByteBuffer content, boolean lastContent, Callback callback); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IdleTimeoutHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IdleTimeoutHandler.java index 04a90f17bc5..e0b0276e46d 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IdleTimeoutHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/IdleTimeoutHandler.java @@ -27,6 +27,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.io.EndPoint; +import org.eclipse.jetty.server.HttpChannel; import org.eclipse.jetty.server.HttpConnection; import org.eclipse.jetty.server.Request; @@ -79,17 +80,9 @@ public class IdleTimeoutHandler extends HandlerWrapper @Override public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { - HttpConnection connection = HttpConnection.getCurrentConnection(); - final EndPoint endp = connection==null?null:connection.getEndPoint(); - - final long idle_timeout; - if (endp==null) - idle_timeout=-1; - else - { - idle_timeout=endp.getIdleTimeout(); - endp.setIdleTimeout(_idleTimeoutMs); - } + final HttpChannel channel = baseRequest.getHttpChannel(); + final long idle_timeout=baseRequest.getHttpChannel().getIdleTimeout(); + channel.setIdleTimeout(_idleTimeoutMs); try { @@ -97,8 +90,6 @@ public class IdleTimeoutHandler extends HandlerWrapper } finally { - if (endp!=null) - { if (_applyToAsync && request.isAsyncStarted()) { request.getAsyncContext().addListener(new AsyncListener() @@ -116,19 +107,18 @@ public class IdleTimeoutHandler extends HandlerWrapper @Override public void onError(AsyncEvent event) throws IOException { - endp.setIdleTimeout(idle_timeout); + channel.setIdleTimeout(idle_timeout); } @Override public void onComplete(AsyncEvent event) throws IOException { - endp.setIdleTimeout(idle_timeout); + channel.setIdleTimeout(idle_timeout); } }); } else - endp.setIdleTimeout(idle_timeout); - } + channel.setIdleTimeout(idle_timeout); } } } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/SharedBlockingCallback.java b/jetty-util/src/main/java/org/eclipse/jetty/util/SharedBlockingCallback.java index 1813f575705..602e48463c1 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/SharedBlockingCallback.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/SharedBlockingCallback.java @@ -23,6 +23,7 @@ import java.io.IOException; import java.io.InterruptedIOException; import java.util.concurrent.CancellationException; import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantLock; @@ -49,6 +50,10 @@ public class SharedBlockingCallback { private static final Logger LOG = Log.getLogger(SharedBlockingCallback.class); + final ReentrantLock _lock = new ReentrantLock(); + final Condition _idle = _lock.newCondition(); + final Condition _complete = _lock.newCondition(); + private static Throwable IDLE = new Throwable() { @@ -77,25 +82,34 @@ public class SharedBlockingCallback } }; - final Blocker _blocker; + Blocker _blocker; public SharedBlockingCallback() { - this(new Blocker()); + _blocker=new Blocker(); } - protected SharedBlockingCallback(Blocker blocker) + protected long getIdleTimeout() { - _blocker=blocker; + return -1; } public Blocker acquire() throws IOException { - _blocker._lock.lock(); + _lock.lock(); + long idle = getIdleTimeout(); try { while (_blocker._state != IDLE) - _blocker._idle.await(); + { + if (idle>0) + { + if (!_idle.await(idle,TimeUnit.MILLISECONDS)) + throw new IOException(new TimeoutException()); + } + else + _idle.await(); + } _blocker._state = null; } catch (final InterruptedException e) @@ -109,7 +123,7 @@ public class SharedBlockingCallback } finally { - _blocker._lock.unlock(); + _lock.unlock(); } return _blocker; } @@ -119,14 +133,11 @@ public class SharedBlockingCallback /** A Closeable Callback. * Uses the auto close mechanism to check block has been called OK. */ - public static class Blocker implements Callback, Closeable + public class Blocker implements Callback, Closeable { - final ReentrantLock _lock = new ReentrantLock(); - final Condition _idle = _lock.newCondition(); - final Condition _complete = _lock.newCondition(); Throwable _state = IDLE; - - public Blocker() + + protected Blocker() { } @@ -183,10 +194,27 @@ public class SharedBlockingCallback LOG.warn("Blocking a NonBlockingThread: ",new Throwable()); _lock.lock(); + long idle = getIdleTimeout(); try { while (_state == null) - _complete.await(); + { + if (idle>0) + { + if (!_complete.await(idle,TimeUnit.MILLISECONDS)) + { + // The callback has not arrived in sufficient time. + // We will synthesize a TimeoutException and then + // create a new Blocker, so that any late arriving callback + // does not cause a problem with the next cycle. + _state=new TimeoutException("No Blocker CB"); + LOG.warn(_state); + _blocker=new Blocker(); + } + } + else + _complete.await(); + } if (_state == SUCCEEDED) return; diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/BlockingWriteCallback.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/BlockingWriteCallback.java index 4fdc68072fc..838afc93e58 100644 --- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/BlockingWriteCallback.java +++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/BlockingWriteCallback.java @@ -20,6 +20,7 @@ package org.eclipse.jetty.websocket.common; import java.io.IOException; +import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.SharedBlockingCallback; import org.eclipse.jetty.websocket.api.WriteCallback; @@ -31,26 +32,55 @@ public class BlockingWriteCallback extends SharedBlockingCallback { public BlockingWriteCallback() { - super(new WriteBlocker()); } public WriteBlocker acquireWriteBlocker() throws IOException { - return (WriteBlocker)acquire(); + return new WriteBlocker(acquire()); } - public static class WriteBlocker extends Blocker implements WriteCallback + public static class WriteBlocker implements WriteCallback, Callback, AutoCloseable { + Blocker blocker; + + WriteBlocker(Blocker blocker) + { + this.blocker=blocker; + } + @Override public void writeFailed(Throwable x) { - failed(x); + blocker.failed(x); } @Override public void writeSuccess() { - succeeded(); + blocker.succeeded(); + } + + @Override + public void succeeded() + { + blocker.succeeded(); + } + + @Override + public void failed(Throwable x) + { + blocker.failed(x); + } + + @Override + public void close() throws IOException + { + blocker.close(); + } + + public void block() throws IOException + { + blocker.block(); } } }