diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneHandler.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneHandler.java index a4bd7d275cb..c8fe4b4b4bd 100644 --- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneHandler.java +++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/OneHandler.java @@ -18,7 +18,6 @@ package org.eclipse.jetty.embedded; -import org.eclipse.jetty.http.HttpCompliance; import org.eclipse.jetty.server.HttpConnectionFactory; import org.eclipse.jetty.server.Server; @@ -27,7 +26,6 @@ public class OneHandler public static void main( String[] args ) throws Exception { Server server = new Server(8080); - server.getConnectors()[0].getConnectionFactory(HttpConnectionFactory.class).setHttpCompliance(HttpCompliance.LEGACY); server.setHandler(new HelloHandler()); server.start(); 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 d380d1775c0..625755fe7ef 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 @@ -265,6 +265,31 @@ public class HttpChannel implements Runnable, HttpOutput.Interceptor { handle(); } + + // TODO Revert once #624 debugged + private static ThreadLocal __dispatchedFrom=new ThreadLocal<>(); + public static Throwable getDispatchedFrom() { return __dispatchedFrom.get(); } + public Runnable getRunnable() + { + Throwable _dispatched = new Throwable(); + return new Runnable() + { + @Override + public void run() + { + try + { + __dispatchedFrom.set(_dispatched); + handle(); + } + finally + { + __dispatchedFrom.set(null); + } + } + }; + } + AtomicReference caller = new AtomicReference<>(); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java index 5a1c6c54d26..296c7e1a8d9 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpChannelState.java @@ -615,7 +615,7 @@ public class HttpChannelState cancelTimeout(event); if (handle) - runInContext(event,_channel); + runInContext(event,_channel.getRunnable()); } public void errorComplete() @@ -887,7 +887,7 @@ public class HttpChannelState protected void scheduleDispatch() { - _channel.execute(_channel); + _channel.execute(_channel.getRunnable()); } protected void scheduleTimeout(AsyncContextEvent event) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java index cec44784117..12c012d39d9 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/HttpInput.java @@ -122,7 +122,7 @@ public class HttpInput extends ServletInputStream implements Runnable { HttpChannel channel = _channelState.getHttpChannel(); Executor executor = channel.getConnector().getServer().getThreadPool(); - executor.execute(channel); + executor.execute(channel.getRunnable()); } 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 c0b95e72189..7bba74f7c8f 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 @@ -860,7 +860,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable { _writeListener = writeListener; if (_channel.getState().onWritePossible()) - _channel.execute(_channel); + _channel.execute(_channel.getRunnable()); } else throw new IllegalStateException(); @@ -1005,7 +1005,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable if (!_state.compareAndSet(OutputState.UNREADY, OutputState.READY)) continue; if (_channel.getState().onWritePossible()) - _channel.execute(_channel); + _channel.execute(_channel.getRunnable()); break; case CLOSED: @@ -1023,7 +1023,7 @@ public class HttpOutput extends ServletOutputStream implements Runnable { _onError=e==null?new IOException():e; if (_channel.getState().onWritePossible()) - _channel.execute(_channel); + _channel.execute(_channel.getRunnable()); } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/LocalAsyncContextTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/LocalAsyncContextTest.java index d27c3353967..7eb8eace336 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/LocalAsyncContextTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/LocalAsyncContextTest.java @@ -18,12 +18,9 @@ package org.eclipse.jetty.server; -import static org.junit.Assert.assertEquals; - import java.io.IOException; import java.io.InputStream; import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Supplier; @@ -37,6 +34,7 @@ import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.server.handler.HandlerWrapper; import org.eclipse.jetty.server.session.SessionHandler; +import org.eclipse.jetty.util.thread.Locker; import org.hamcrest.Matchers; import org.junit.After; import org.junit.Assert; @@ -45,6 +43,10 @@ import org.junit.Test; public class LocalAsyncContextTest { + private final Locker _completeLock = new Locker(); + private Throwable __completed; + private Throwable __dispatched; + private final AtomicReference __completed1 = new AtomicReference<>(); protected Server _server; protected SuspendHandler _handler; protected Connector _connector; @@ -54,7 +56,7 @@ public class LocalAsyncContextTest { _server = new Server(); _connector = initConnector(); - _server.setConnectors(new Connector[]{ _connector }); + _server.addConnector(_connector); SessionHandler session = new SessionHandler(); _handler = new SuspendHandler(); @@ -63,7 +65,10 @@ public class LocalAsyncContextTest _server.setHandler(session); _server.start(); - __completed.set(null); + try (Locker.Lock lock = _completeLock.lock()) + { + __completed = null; + } __completed1.set(null); } @@ -87,10 +92,17 @@ public class LocalAsyncContextTest _handler.setSuspendFor(1000); _handler.setResumeAfter(-1); _handler.setCompleteAfter(-1); - response=process(null); - check(response,"TIMEOUT"); - spinAssertEquals(1,()->{return __completed.get()==null?0:1;}); - spinAssertEquals(1,()->{return __completed1.get()==null?0:1;}); + response = process(null); + check(response, "TIMEOUT"); + + spinAssertEquals(1, () -> + { + try (Locker.Lock lock = _completeLock.lock()) + { + return __completed == null ? 0 : 1; + } + }); + spinAssertEquals(1, () -> __completed1.get() == null ? 0 : 1); } @Test @@ -101,8 +113,8 @@ public class LocalAsyncContextTest _handler.setSuspendFor(10000); _handler.setResumeAfter(0); _handler.setCompleteAfter(-1); - response=process(null); - check(response,"STARTASYNC","DISPATCHED"); + response = process(null); + check(response, "STARTASYNC", "DISPATCHED"); } @Test @@ -113,8 +125,8 @@ public class LocalAsyncContextTest _handler.setSuspendFor(10000); _handler.setResumeAfter(100); _handler.setCompleteAfter(-1); - response=process(null); - check(response,"STARTASYNC","DISPATCHED"); + response = process(null); + check(response, "STARTASYNC", "DISPATCHED"); } @Test @@ -125,8 +137,8 @@ public class LocalAsyncContextTest _handler.setSuspendFor(10000); _handler.setResumeAfter(-1); _handler.setCompleteAfter(0); - response=process(null); - check(response,"STARTASYNC","COMPLETED"); + response = process(null); + check(response, "STARTASYNC", "COMPLETED"); } @Test @@ -137,9 +149,8 @@ public class LocalAsyncContextTest _handler.setSuspendFor(10000); _handler.setResumeAfter(-1); _handler.setCompleteAfter(200); - response=process(null); - check(response,"STARTASYNC","COMPLETED"); - + response = process(null); + check(response, "STARTASYNC", "COMPLETED"); } @Test @@ -150,8 +161,8 @@ public class LocalAsyncContextTest _handler.setRead(-1); _handler.setResumeAfter(0); _handler.setCompleteAfter(-1); - response=process("wibble"); - check(response,"STARTASYNC","DISPATCHED"); + response = process("wibble"); + check(response, "STARTASYNC", "DISPATCHED"); } @Test @@ -162,9 +173,8 @@ public class LocalAsyncContextTest _handler.setRead(-1); _handler.setResumeAfter(100); _handler.setCompleteAfter(-1); - response=process("wibble"); - check(response,"DISPATCHED"); - + response = process("wibble"); + check(response, "DISPATCHED"); } @Test @@ -175,35 +185,35 @@ public class LocalAsyncContextTest _handler.setRead(-1); _handler.setResumeAfter(-1); _handler.setCompleteAfter(0); - response=process("wibble"); - check(response,"COMPLETED"); + response = process("wibble"); + check(response, "COMPLETED"); _handler.setResumeAfter(-1); _handler.setCompleteAfter(100); - response=process("wibble"); - check(response,"COMPLETED"); + response = process("wibble"); + check(response, "COMPLETED"); _handler.setRead(6); _handler.setResumeAfter(0); _handler.setCompleteAfter(-1); - response=process("wibble"); - check(response,"DISPATCHED"); + response = process("wibble"); + check(response, "DISPATCHED"); _handler.setResumeAfter(100); _handler.setCompleteAfter(-1); - response=process("wibble"); - check(response,"DISPATCHED"); + response = process("wibble"); + check(response, "DISPATCHED"); _handler.setResumeAfter(-1); _handler.setCompleteAfter(0); - response=process("wibble"); - check(response,"COMPLETED"); + response = process("wibble"); + check(response, "COMPLETED"); _handler.setResumeAfter(-1); _handler.setCompleteAfter(100); - response=process("wibble"); - check(response,"COMPLETED"); + response = process("wibble"); + check(response, "COMPLETED"); } @Test @@ -218,345 +228,289 @@ public class LocalAsyncContextTest _handler.setSuspendFor2(1000); _handler.setResumeAfter2(200); _handler.setCompleteAfter2(-1); - response=process(null); - check(response,"STARTASYNC","DISPATCHED","startasync","STARTASYNC","DISPATCHED"); - spinAssertEquals(1,()->{return __completed.get()==null?0:1;}); - spinAssertEquals(0,()->{return __completed1.get()==null?0:1;}); + response = process(null); + check(response, "STARTASYNC", "DISPATCHED", "startasync", "STARTASYNC2", "DISPATCHED"); + spinAssertEquals(1, () -> + { + try (Locker.Lock lock = _completeLock.lock()) + { + return __completed == null ? 0 : 1; + } + }); + spinAssertEquals(0, () -> __completed1.get() == null ? 0 : 1); } - protected void check(String response,String... content) + protected void check(String response, String... content) { - Assert.assertThat(response,Matchers.startsWith("HTTP/1.1 200 OK")); - int i=0; - for (String m:content) + Assert.assertThat(response, Matchers.startsWith("HTTP/1.1 200 OK")); + int i = 0; + for (String m : content) { - Assert.assertThat(response,Matchers.containsString(m)); - i=response.indexOf(m,i); - i+=m.length(); + Assert.assertThat(response, Matchers.containsString(m)); + i = response.indexOf(m, i); + i += m.length(); } } private synchronized String process(String content) throws Exception { String request = "GET / HTTP/1.1\r\n" + - "Host: localhost\r\n"+ - "Connection: close\r\n"; + "Host: localhost\r\n" + + "Connection: close\r\n"; - if (content==null) - request+="\r\n"; + if (content == null) + request += "\r\n"; else - request+="Content-Length: "+content.length()+"\r\n" +"\r\n" + content; + request += "Content-Length: " + content.length() + "\r\n" + "\r\n" + content; - String response=getResponse(request); - return response; + return getResponse(request); } protected String getResponse(String request) throws Exception { - LocalConnector connector=(LocalConnector)_connector; + LocalConnector connector = (LocalConnector)_connector; LocalConnector.LocalEndPoint endp = connector.executeRequest(request); endp.waitUntilClosed(); return endp.takeOutputString(); } - private static class SuspendHandler extends HandlerWrapper + private class SuspendHandler extends HandlerWrapper { private int _read; - private long _suspendFor=-1; - private long _resumeAfter=-1; - private long _completeAfter=-1; - private long _suspendFor2=-1; - private long _resumeAfter2=-1; - private long _completeAfter2=-1; + private long _suspendFor = -1; + private long _resumeAfter = -1; + private long _completeAfter = -1; + private long _suspendFor2 = -1; + private long _resumeAfter2 = -1; + private long _completeAfter2 = -1; public SuspendHandler() { } - public int getRead() - { - return _read; - } - public void setRead(int read) { _read = read; } - public long getSuspendFor() - { - return _suspendFor; - } - public void setSuspendFor(long suspendFor) { _suspendFor = suspendFor; } - public long getResumeAfter() - { - return _resumeAfter; - } - public void setResumeAfter(long resumeAfter) { _resumeAfter = resumeAfter; } - public long getCompleteAfter() - { - return _completeAfter; - } - public void setCompleteAfter(long completeAfter) { _completeAfter = completeAfter; } - - - /* ------------------------------------------------------------ */ - /** Get the suspendFor2. - * @return the suspendFor2 - */ - public long getSuspendFor2() - { - return _suspendFor2; - } - - - /* ------------------------------------------------------------ */ - /** Set the suspendFor2. - * @param suspendFor2 the suspendFor2 to set - */ public void setSuspendFor2(long suspendFor2) { _suspendFor2 = suspendFor2; } - - /* ------------------------------------------------------------ */ - /** Get the resumeAfter2. - * @return the resumeAfter2 - */ - public long getResumeAfter2() - { - return _resumeAfter2; - } - - - /* ------------------------------------------------------------ */ - /** Set the resumeAfter2. - * @param resumeAfter2 the resumeAfter2 to set - */ public void setResumeAfter2(long resumeAfter2) { _resumeAfter2 = resumeAfter2; } - - /* ------------------------------------------------------------ */ - /** Get the completeAfter2. - * @return the completeAfter2 - */ - public long getCompleteAfter2() - { - return _completeAfter2; - } - - - /* ------------------------------------------------------------ */ - /** Set the completeAfter2. - * @param completeAfter2 the completeAfter2 to set - */ public void setCompleteAfter2(long completeAfter2) { _completeAfter2 = completeAfter2; } - - /* ------------------------------------------------------------ */ @Override public void handle(String target, final Request baseRequest, final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException { - try + if (DispatcherType.REQUEST.equals(baseRequest.getDispatcherType())) { - if (DispatcherType.REQUEST.equals(baseRequest.getDispatcherType())) + if (_read > 0) { - if (_read>0) - { - byte[] buf=new byte[_read]; - request.getInputStream().read(buf); - } - else if (_read<0) - { - InputStream in = request.getInputStream(); - int b=in.read(); - while(b!=-1) - b=in.read(); - } + int read = _read; + byte[] buf = new byte[read]; + while (read > 0) + read -= request.getInputStream().read(buf); + } + else if (_read < 0) + { + InputStream in = request.getInputStream(); + int b = in.read(); + while (b != -1) + b = in.read(); + } + final AsyncContext asyncContext = baseRequest.startAsync(); + response.getOutputStream().println("STARTASYNC"); + asyncContext.addListener(__asyncListener); + asyncContext.addListener(__asyncListener1); + if (_suspendFor > 0) + asyncContext.setTimeout(_suspendFor); + + if (_completeAfter > 0) + { + new Thread() + { + @Override + public void run() + { + try + { + Thread.sleep(_completeAfter); + response.getOutputStream().println("COMPLETED"); + response.setStatus(200); + baseRequest.setHandled(true); + asyncContext.complete(); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + }.start(); + } + else if (_completeAfter == 0) + { + response.getOutputStream().println("COMPLETED"); + response.setStatus(200); + baseRequest.setHandled(true); + asyncContext.complete(); + } + + if (_resumeAfter > 0) + { + new Thread() + { + @Override + public void run() + { + try + { + Thread.sleep(_resumeAfter); + if (((HttpServletRequest)asyncContext.getRequest()).getSession(true).getId() != null) + asyncContext.dispatch(); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + }.start(); + } + else if (_resumeAfter == 0) + { + asyncContext.dispatch(); + } + } + else + { + if (request.getAttribute("TIMEOUT") != null) + response.getOutputStream().println("TIMEOUT"); + else + response.getOutputStream().println("DISPATCHED"); + + if (_suspendFor2 >= 0) + { final AsyncContext asyncContext = baseRequest.startAsync(); - response.getOutputStream().println("STARTASYNC"); - asyncContext.addListener(__asyncListener); - asyncContext.addListener(__asyncListener1); - if (_suspendFor>0) - asyncContext.setTimeout(_suspendFor); + response.getOutputStream().println("STARTASYNC2"); + if (_suspendFor2 > 0) + asyncContext.setTimeout(_suspendFor2); + _suspendFor2 = -1; - - if (_completeAfter>0) + if (_completeAfter2 > 0) { - new Thread() { + new Thread() + { @Override public void run() { try { - Thread.sleep(_completeAfter); - response.getOutputStream().println("COMPLETED"); + Thread.sleep(_completeAfter2); + response.getOutputStream().println("COMPLETED2"); response.setStatus(200); baseRequest.setHandled(true); asyncContext.complete(); } - catch(Exception e) + catch (Exception e) { e.printStackTrace(); } } }.start(); } - else if (_completeAfter==0) + else if (_completeAfter2 == 0) { - response.getOutputStream().println("COMPLETED"); + response.getOutputStream().println("COMPLETED2"); response.setStatus(200); baseRequest.setHandled(true); asyncContext.complete(); } - if (_resumeAfter>0) + if (_resumeAfter2 > 0) { - new Thread() { + new Thread() + { @Override public void run() { try { - Thread.sleep(_resumeAfter); - if(((HttpServletRequest)asyncContext.getRequest()).getSession(true).getId()!=null) - asyncContext.dispatch(); + Thread.sleep(_resumeAfter2); + asyncContext.dispatch(); } - catch(Exception e) + catch (Exception e) { e.printStackTrace(); } } }.start(); } - else if (_resumeAfter==0) + else if (_resumeAfter2 == 0) { asyncContext.dispatch(); } } else { - if (request.getAttribute("TIMEOUT")!=null) - { - response.getOutputStream().println("TIMEOUT"); - } - else - { - response.getOutputStream().println("DISPATCHED"); - } - - if (_suspendFor2>=0) - { - final AsyncContext asyncContext = baseRequest.startAsync(); - response.getOutputStream().println("STARTASYNC2"); - if (_suspendFor2>0) - asyncContext.setTimeout(_suspendFor2); - _suspendFor2=-1; - - if (_completeAfter2>0) - { - new Thread() { - @Override - public void run() - { - try - { - Thread.sleep(_completeAfter2); - response.getOutputStream().println("COMPLETED2"); - response.setStatus(200); - baseRequest.setHandled(true); - asyncContext.complete(); - } - catch(Exception e) - { - e.printStackTrace(); - } - } - }.start(); - } - else if (_completeAfter2==0) - { - response.getOutputStream().println("COMPLETED2"); - response.setStatus(200); - baseRequest.setHandled(true); - asyncContext.complete(); - } - - if (_resumeAfter2>0) - { - new Thread() { - @Override - public void run() - { - try - { - Thread.sleep(_resumeAfter2); - asyncContext.dispatch(); - } - catch(Exception e) - { - e.printStackTrace(); - } - } - }.start(); - } - else if (_resumeAfter2==0) - { - asyncContext.dispatch(); - } - } - else - { - response.setStatus(200); - baseRequest.setHandled(true); - } + response.setStatus(200); + baseRequest.setHandled(true); } } - finally - { - } } } - static AtomicReference __completed = new AtomicReference<>(); - static AtomicReference __completed1 = new AtomicReference<>(); - - private static AsyncListener __asyncListener = new AsyncListener() + private AsyncListener __asyncListener = new AsyncListener() { @Override public void onComplete(AsyncEvent event) throws IOException { Throwable complete = new Throwable(); - if (!__completed.compareAndSet(null,complete)) + Throwable dispatched = HttpChannel.getDispatchedFrom(); + try (Locker.Lock lock = _completeLock.lock()) { - __completed.get().printStackTrace(); - complete.printStackTrace(); - __completed.set(null); - throw new IllegalStateException(); + if (__completed == null) + { + __completed = complete; + __dispatched = dispatched; + } + else + { + System.err.println("First onCompleted dispatched from:"); + if (__dispatched != null) + __dispatched.printStackTrace(); + System.err.println("First onCompleted:"); + __completed.printStackTrace(); + System.err.println("Second onCompleted dispatched from:"); + if (dispatched != null) + dispatched.printStackTrace(); + complete.printStackTrace(); + throw new IllegalStateException(); + } } } @@ -564,12 +518,27 @@ public class LocalAsyncContextTest public void onError(AsyncEvent event) throws IOException { Throwable complete = new Throwable(); - if (!__completed.compareAndSet(null,complete)) + Throwable dispatched = HttpChannel.getDispatchedFrom(); + try (Locker.Lock lock = _completeLock.lock()) { - __completed.get().printStackTrace(); - complete.printStackTrace(); - __completed.set(null); - throw new IllegalStateException(); + if (__completed == null) + { + __completed = complete; + __dispatched = dispatched; + } + else + { + System.err.println("First onCompleted dispatched from:"); + if (__dispatched != null) + __dispatched.printStackTrace(); + System.err.println("First onCompleted:"); + __completed.printStackTrace(); + System.err.println("Second onCompleted dispatched from:"); + if (dispatched != null) + dispatched.printStackTrace(); + complete.printStackTrace(); + throw new IllegalStateException(); + } } } @@ -583,18 +552,18 @@ public class LocalAsyncContextTest @Override public void onTimeout(AsyncEvent event) throws IOException { - event.getSuppliedRequest().setAttribute("TIMEOUT",Boolean.TRUE); + event.getSuppliedRequest().setAttribute("TIMEOUT", Boolean.TRUE); event.getAsyncContext().dispatch(); } }; - private static AsyncListener __asyncListener1 = new AsyncListener() + private AsyncListener __asyncListener1 = new AsyncListener() { @Override public void onComplete(AsyncEvent event) throws IOException { Throwable complete = new Throwable(); - if (!__completed1.compareAndSet(null,complete)) + if (!__completed1.compareAndSet(null, complete)) { __completed1.get().printStackTrace(); complete.printStackTrace(); @@ -607,7 +576,7 @@ public class LocalAsyncContextTest public void onError(AsyncEvent event) throws IOException { Throwable complete = new Throwable(); - if (!__completed1.compareAndSet(null,complete)) + if (!__completed1.compareAndSet(null, complete)) { __completed1.get().printStackTrace(); complete.printStackTrace(); @@ -615,7 +584,7 @@ public class LocalAsyncContextTest throw new IllegalStateException(); } } - + @Override public void onStartAsync(AsyncEvent event) throws IOException { @@ -625,24 +594,23 @@ public class LocalAsyncContextTest public void onTimeout(AsyncEvent event) throws IOException { } - }; static void spinAssertEquals(T expected, Supplier actualSupplier) { - spinAssertEquals(expected,actualSupplier,10,TimeUnit.SECONDS); + spinAssertEquals(expected, actualSupplier, 10, TimeUnit.SECONDS); } - + static void spinAssertEquals(T expected, Supplier actualSupplier, long waitFor, TimeUnit units) { long now = System.nanoTime(); - long end = now+units.toNanos(waitFor); - T actual=null; - while(now < end) + long end = now + units.toNanos(waitFor); + T actual = null; + while (now < end) { - actual=actualSupplier.get(); - if (actual==null && expected==null || - actual!=null && actual.equals(expected)) + actual = actualSupplier.get(); + if (actual == null && expected == null || + actual != null && actual.equals(expected)) break; try { @@ -650,10 +618,11 @@ public class LocalAsyncContextTest } catch (InterruptedException e) { + // Ignored } now = System.nanoTime(); } - - assertEquals(expected,actual); + + Assert.assertEquals(expected, actual); } } diff --git a/jetty-start/src/test/resources/usecases/empty/unrelated.txt b/jetty-start/src/test/resources/usecases/empty/unrelated.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaInfConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaInfConfiguration.java index 6e77a6d2813..332f0f505ac 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaInfConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaInfConfiguration.java @@ -181,7 +181,7 @@ public class MetaInfConfiguration extends AbstractConfiguration { //Resource represents a packed jar URI uri = target.getURI(); - resourcesDir = Resource.newResource("jar:"+uri+"!/META-INF/resources"); + resourcesDir = Resource.newResource(uriJarPrefix(uri,"!/META-INF/resources")); } if (!resourcesDir.exists() || !resourcesDir.isDirectory()) @@ -252,7 +252,7 @@ public class MetaInfConfiguration extends AbstractConfiguration else { URI uri = jar.getURI(); - webFrag = Resource.newResource("jar:"+uri+"!/META-INF/web-fragment.xml"); + webFrag = Resource.newResource(uriJarPrefix(uri,"!/META-INF/web-fragment.xml")); } if (!webFrag.exists() || webFrag.isDirectory()) { @@ -401,8 +401,9 @@ public class MetaInfConfiguration extends AbstractConfiguration public Collection getTlds (URI uri) throws IOException { HashSet tlds = new HashSet(); - - URL url = new URL("jar:"+uri+"!/"); + + String jarUri = uriJarPrefix(uri, "!/"); + URL url = new URL(jarUri); JarURLConnection jarConn = (JarURLConnection) url.openConnection(); jarConn.setUseCaches(Resource.getDefaultUseCaches()); JarFile jarFile = jarConn.getJarFile(); @@ -413,11 +414,21 @@ public class MetaInfConfiguration extends AbstractConfiguration String name = e.getName(); if (name.startsWith("META-INF") && name.endsWith(".tld")) { - tlds.add(new URL("jar:"+uri+"!/"+name)); + tlds.add(new URL(jarUri + name)); } } if (!Resource.getDefaultUseCaches()) jarFile.close(); return tlds; } + + private String uriJarPrefix(URI uri, String suffix) + { + String uriString = uri.toString(); + if (uriString.startsWith("jar:")) { + return uriString + suffix; + } else { + return "jar:" + uriString + suffix; + } + } } diff --git a/tests/test-jmx/jmx-webapp-it/pom.xml b/tests/test-jmx/jmx-webapp-it/pom.xml index e5185756c12..695faa3f592 100644 --- a/tests/test-jmx/jmx-webapp-it/pom.xml +++ b/tests/test-jmx/jmx-webapp-it/pom.xml @@ -14,17 +14,18 @@ UTF-8 UTF-8 ${project.groupId}.jmx.webapp.it - ${project.basedir}/src/test/scripts ${project.build.directory}/test-base - ${project.build.directory}/test-home org.eclipse.jetty - jetty-distribution + jetty-annotations + ${project.version} + + + org.eclipse.jetty + jetty-jmx ${project.version} - zip - runtime org.eclipse.jetty.tests @@ -61,22 +62,6 @@ ${test-base-dir}/webapps - - unpack-jetty-distro - process-test-resources - - unpack-dependencies - - - jetty-distribution - runtime - zip - true - ${test-home-dir} - true - true - - @@ -91,98 +76,6 @@ - - org.apache.maven.plugins - maven-antrun-plugin - - - start-jetty - pre-integration-test - - run - - - - - - Integration Test : Setup Jetty - - - - - - - - - Integration Test : Starting Jetty ... - - - - - - - - - - - Integration Test : Jetty is now available - - - - - stop-jetty - post-integration-test - - run - - - - - - Integration Test : Stop Jetty - - - - - - - - - - - - - - - it-windows - - - Windows - - - - cmd - /c - start-jetty.bat - stop-jetty.bat - - - - it-unix - - - unix - - - - sh - -- - setup-jetty.sh - start-jetty.sh - stop-jetty.sh - - - diff --git a/tests/test-jmx/jmx-webapp-it/src/test/java/org/eclipse/jetty/test/jmx/JmxIT.java b/tests/test-jmx/jmx-webapp-it/src/test/java/org/eclipse/jetty/test/jmx/JmxIT.java index 826b82381f1..3c7c462e8a2 100644 --- a/tests/test-jmx/jmx-webapp-it/src/test/java/org/eclipse/jetty/test/jmx/JmxIT.java +++ b/tests/test-jmx/jmx-webapp-it/src/test/java/org/eclipse/jetty/test/jmx/JmxIT.java @@ -24,7 +24,9 @@ import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.startsWith; import static org.junit.Assert.assertThat; -import java.io.IOException; +import java.io.File; +import java.lang.management.ManagementFactory; +import java.net.URI; import javax.management.MBeanServerConnection; import javax.management.ObjectName; @@ -32,6 +34,14 @@ import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.toolchain.test.MavenTestingUtils; +import org.eclipse.jetty.toolchain.test.SimpleRequest; +import org.eclipse.jetty.webapp.Configuration; +import org.eclipse.jetty.webapp.WebAppContext; +import org.eclipse.jetty.jmx.ConnectorServer; +import org.eclipse.jetty.jmx.MBeanContainer; +import org.eclipse.jetty.server.NetworkConnector; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; @@ -41,26 +51,78 @@ import org.junit.Test; */ public class JmxIT { - private static JMXConnector jmxc; - private static MBeanServerConnection mbsc; + private static JMXConnector __jmxc; + private static MBeanServerConnection __mbsc; + private static Server __server; + private static int __port; @BeforeClass - public static void connectToMBeanServer() throws IOException + public static void connectToMBeanServer() throws Exception { + startJetty(); JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://localhost:1099/jndi/rmi://localhost:1099/jmxrmi"); - jmxc = JMXConnectorFactory.connect(url,null); - mbsc = jmxc.getMBeanServerConnection(); + __jmxc = JMXConnectorFactory.connect(url,null); + __mbsc = __jmxc.getMBeanServerConnection(); } @AfterClass - public static void disconnectFromMBeanServer() throws IOException + public static void disconnectFromMBeanServer() throws Exception { - jmxc.close(); + stopJetty(); + __jmxc.close(); + } + + public static void startJetty() throws Exception + { + File target = MavenTestingUtils.getTargetDir(); + File jettyBase = new File (target, "test-base"); + File webapps = new File (jettyBase, "webapps"); + File war = new File (webapps, "jmx-webapp.war"); + + //create server instance + __server = new Server(0); + + //set up the webapp + WebAppContext context = new WebAppContext(); + + context.setWar(war.getCanonicalPath()); + context.setContextPath("/jmx-webapp"); + + Configuration.ClassList classlist = Configuration.ClassList + .setServerDefault(__server); + classlist.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration", + "org.eclipse.jetty.annotations.AnnotationConfiguration"); + + context.setAttribute( + "org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", + ".*/javax.servlet-[^/]*\\.jar$|.*/servlet-api-[^/]*\\.jar$"); + __server.setHandler(context); + + //set up jmx remote + MBeanContainer mbContainer = new MBeanContainer(ManagementFactory.getPlatformMBeanServer()); + __server.addBean(mbContainer); + + JMXServiceURL serviceUrl = new JMXServiceURL("rmi", "localhost", 1099, "/jndi/rmi://localhost:1099/jmxrmi"); + ConnectorServer jmxConnServer = new ConnectorServer(serviceUrl, "org.eclipse.jetty.jmx:name=rmiconnectorserver"); + __server.addBean(jmxConnServer); + + //start server + __server.start(); + + //remember chosen port + __port = ((NetworkConnector)__server.getConnectors()[0]).getLocalPort(); + } + + + public static void stopJetty () throws Exception + { + if (__server != null) + __server.stop(); } private String getStringAttribute(ObjectName objName, String attrName) throws Exception { - Object val = mbsc.getAttribute(objName,attrName); + Object val = __mbsc.getAttribute(objName,attrName); assertThat(attrName,val,notNullValue()); assertThat(attrName,val,instanceOf(String.class)); return (String)val; @@ -68,18 +130,25 @@ public class JmxIT private int getIntegerAttribute(ObjectName objName, String attrName) throws Exception { - Object val = mbsc.getAttribute(objName,attrName); + Object val = __mbsc.getAttribute(objName,attrName); assertThat(attrName,val,notNullValue()); assertThat(attrName,val,instanceOf(Integer.class)); return (Integer)val; } + @Test + public void testBasic() throws Exception + { + URI serverURI = new URI("http://localhost:"+String.valueOf(__port)+"/jmx-webapp/"); + SimpleRequest req = new SimpleRequest(serverURI); + assertThat(req.getString("ping"),startsWith("Servlet Pong at ")); + } + @Test public void testObtainRunningServerVersion() throws Exception { ObjectName serverName = new ObjectName("org.eclipse.jetty.server:type=server,id=0"); String version = getStringAttribute(serverName,"version"); - System.err.println("Running version: " + version); assertThat("Version",version,startsWith("9.4.")); } @@ -117,7 +186,7 @@ public class JmxIT // Get initial count int count = getIntegerAttribute(pingerName,"count"); // Operations - Object val = mbsc.invoke(pingerName,"ping",null,null); + Object val = __mbsc.invoke(pingerName,"ping",null,null); assertThat("ping() return",val.toString(),startsWith("Pong")); // Attributes assertThat("count",getIntegerAttribute(pingerName,"count"),is(count+1)); @@ -134,7 +203,7 @@ public class JmxIT // Get initial count int count = getIntegerAttribute(echoerName,"count"); // Operations - Object val = mbsc.invoke(echoerName,"echo",new Object[]{"Its Me"},new String[]{String.class.getName()}); + Object val = __mbsc.invoke(echoerName,"echo",new Object[]{"Its Me"},new String[]{String.class.getName()}); assertThat("echo() return",val.toString(),is("Its Me")); // Attributes assertThat("count",getIntegerAttribute(echoerName,"count"),is(count+1)); diff --git a/tests/test-jmx/jmx-webapp-it/src/test/java/org/eclipse/jetty/test/jmx/PingIT.java b/tests/test-jmx/jmx-webapp-it/src/test/java/org/eclipse/jetty/test/jmx/PingIT.java deleted file mode 100644 index fb104f967ae..00000000000 --- a/tests/test-jmx/jmx-webapp-it/src/test/java/org/eclipse/jetty/test/jmx/PingIT.java +++ /dev/null @@ -1,41 +0,0 @@ -// -// ======================================================================== -// Copyright (c) 1995-2016 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.test.jmx; - -import static org.hamcrest.Matchers.startsWith; -import static org.junit.Assert.assertThat; - -import java.net.URI; - -import org.eclipse.jetty.toolchain.test.SimpleRequest; -import org.junit.Test; - -/** - * Basic tests for a simple Servlet with no JMX involved (yet) - */ -public class PingIT -{ - @Test - public void testBasic() throws Exception - { - URI serverURI = new URI("http://localhost:58080/jmx-webapp/"); - SimpleRequest req = new SimpleRequest(serverURI); - assertThat(req.getString("ping"),startsWith("Servlet Pong at ")); - } -} diff --git a/tests/test-jmx/jmx-webapp-it/src/test/scripts/setup-jetty.sh b/tests/test-jmx/jmx-webapp-it/src/test/scripts/setup-jetty.sh deleted file mode 100755 index 22beac14dbe..00000000000 --- a/tests/test-jmx/jmx-webapp-it/src/test/scripts/setup-jetty.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env bash - -JAVA_HOME=$1 -JETTY_HOME=$2 -JETTY_BASE=$3 - -echo \${java.home} : $JAVA_HOME -echo \${jetty.home} : $JETTY_HOME -echo \${jetty.base} : $JETTY_BASE - -cd "$JETTY_BASE" - -"$JAVA_HOME/bin/java" -jar "$JETTY_HOME/start.jar" \ - --approve-all-licenses \ - --add-to-start=deploy,http,annotations,jmx,jmx-remote,logging - -"$JAVA_HOME/bin/java" -jar "$JETTY_HOME/start.jar" \ - --version - diff --git a/tests/test-jmx/jmx-webapp-it/src/test/scripts/start-jetty.sh b/tests/test-jmx/jmx-webapp-it/src/test/scripts/start-jetty.sh deleted file mode 100755 index ea7843bf256..00000000000 --- a/tests/test-jmx/jmx-webapp-it/src/test/scripts/start-jetty.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/usr/bin/env bash - -JAVA_HOME=$1 -JETTY_HOME=$2 -JETTY_BASE=$3 - -echo \${java.home} : $JAVA_HOME -echo \${jetty.home} : $JETTY_HOME -echo \${jetty.base} : $JETTY_BASE - -cd "$JETTY_BASE" - -"$JAVA_HOME/bin/java" -jar "$JETTY_HOME/start.jar" \ - jetty.http.port=58080 \ - STOP.PORT=58181 STOP.KEY=it - - diff --git a/tests/test-jmx/jmx-webapp-it/src/test/scripts/stop-jetty.sh b/tests/test-jmx/jmx-webapp-it/src/test/scripts/stop-jetty.sh deleted file mode 100755 index 32e40774908..00000000000 --- a/tests/test-jmx/jmx-webapp-it/src/test/scripts/stop-jetty.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/usr/bin/env bash - -JAVA_HOME=$1 -JETTY_HOME=$2 -JETTY_BASE=$3 - -cd "$JETTY_BASE" -"$JAVA_HOME/bin/java" -jar "$JETTY_HOME/start.jar" \ - --stop STOP.PORT=58181 STOP.KEY=it - -