diff --git a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/MaxConcurrentStreamsTest.java b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/MaxConcurrentStreamsTest.java index c456d0261ab..82cdda72268 100644 --- a/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/MaxConcurrentStreamsTest.java +++ b/jetty-http2/http2-http-client-transport/src/test/java/org/eclipse/jetty/http2/client/http/MaxConcurrentStreamsTest.java @@ -52,7 +52,7 @@ public class MaxConcurrentStreamsTest extends AbstractTest @Test public void testOneConcurrentStream() throws Exception { - long sleep = 1000; + long sleep = 2000; start(1, new AbstractHandler() { @Override diff --git a/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded.mod b/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded.mod new file mode 100644 index 00000000000..76441062683 --- /dev/null +++ b/jetty-infinispan/src/main/config/modules/session-store-infinispan-embedded.mod @@ -0,0 +1,21 @@ +[description] +Enables session data store in a local Infinispan cache + +[provides] +session-store + +[depend] +sessions +sessions/infinispan/default + +[files] +maven://org.infinispan/infinispan-embedded/7.1.1.Final|lib/infinispan/infinispan-embedded-7.1.1.Final.jar + +[lib] +lib/jetty-infinispan-${jetty.version}.jar +lib/infinispan/*.jar + +[license] +Infinispan is an open source project hosted on Github and released under the Apache 2.0 license. +http://infinispan.org/ +http://www.apache.org/licenses/LICENSE-2.0.html diff --git a/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote.mod b/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote.mod new file mode 100644 index 00000000000..12ff46de108 --- /dev/null +++ b/jetty-infinispan/src/main/config/modules/session-store-infinispan-remote.mod @@ -0,0 +1,27 @@ +[description] +Enables session data store in a remote Infinispan cache + +[provides] +session-store + +[depend] +sessions +sessions/infinispan/remote + +[files] +maven://org.infinispan/infinispan-remote/7.1.1.Final|lib/infinispan/infinispan-remote-7.1.1.Final.jar + +[lib] +lib/jetty-infinispan-${jetty.version}.jar +lib/infinispan/*.jar + +[license] +Infinispan is an open source project hosted on Github and released under the Apache 2.0 license. +http://infinispan.org/ +http://www.apache.org/licenses/LICENSE-2.0.html + + +[ini-template] +#jetty.session.remoteInfinispanCache.name=sessions +#jetty.session.infinispanIdleTimeout.seconds=0 +#jetty.session.gracePeriod.seconds=3600 diff --git a/jetty-infinispan/src/main/config/modules/session-store-infinispan.mod b/jetty-infinispan/src/main/config/modules/session-store-infinispan.mod deleted file mode 100644 index 168265d136a..00000000000 --- a/jetty-infinispan/src/main/config/modules/session-store-infinispan.mod +++ /dev/null @@ -1,37 +0,0 @@ -[description] -Enables session data store in an Infinispan cache - -[provides] -session-store - -[depend] -sessions -sessions/infinispan/${cache-type} - -[files] -maven://org.infinispan/infinispan-core/7.1.1.Final|lib/infinispan/infinispan-core-7.1.1.Final.jar -maven://org.infinispan/infinispan-commons/7.1.1.Final|lib/infinispan/infinispan-commons-7.1.1.Final.jar -maven://org.jgroups/jgroups/3.6.1.Final|lib/infinispan/jgroups-3.6.1.Final.jar -maven://org.jboss.marshalling/jboss-marshalling-osgi/1.4.4.Final|lib/infinispan/jboss-marshalling-osgi-1.4.4.Final.jar -maven://org.jboss.logging/jboss-logging/3.1.2.GA|lib/infinispan/jboss-logging-3.1.2.GA.jar - -[lib] -lib/jetty-infinispan-${jetty.version}.jar -lib/infinispan/*.jar - -[license] -Infinispan is an open source project hosted on Github and released under the Apache 2.0 license. -http://infinispan.org/ -http://www.apache.org/licenses/LICENSE-2.0.html - - -[ini] -cache-type=default - -[ini-template] -cache-type=default - -#cache-type=remote -#jetty.session.remoteInfinispanCache.name=sessions -#jetty.session.infinispanIdleTimeout.seconds=0 -#jetty.session.gracePeriod.seconds=3600 diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/ByteArrayEndPointTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/ByteArrayEndPointTest.java index 2a49e8b351f..d7321f1a38d 100644 --- a/jetty-io/src/test/java/org/eclipse/jetty/io/ByteArrayEndPointTest.java +++ b/jetty-io/src/test/java/org/eclipse/jetty/io/ByteArrayEndPointTest.java @@ -268,7 +268,7 @@ public class ByteArrayEndPointTest @Test public void testIdle() throws Exception { - long idleTimeout = 500; + long idleTimeout = 1500; ByteArrayEndPoint endp = new ByteArrayEndPoint(_scheduler, idleTimeout); endp.addInput("test"); endp.setGrowOutput(false); @@ -284,7 +284,7 @@ public class ByteArrayEndPointTest FutureCallback fcb = new FutureCallback(); endp.fillInterested(fcb); - fcb.get(100,TimeUnit.MILLISECONDS); + fcb.get(idleTimeout,TimeUnit.MILLISECONDS); assertTrue(fcb.isDone()); assertEquals(null, fcb.get()); assertEquals(4, endp.fill(buffer)); diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntry.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntry.java index 944452a5aa6..c6008881def 100644 --- a/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntry.java +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/jndi/NamingEntry.java @@ -55,9 +55,18 @@ public abstract class NamingEntry } + /** + * Create a naming entry. + * + * @param scope an object representing the scope of the name to be bound into jndi, where null means jvm scope. + * @param jndiName the name that will be associated with an object bound into jndi + * @throws NamingException + */ protected NamingEntry (Object scope, String jndiName) throws NamingException { + if (jndiName == null) + throw new NamingException("jndi name is null"); this._scope=scope; this._jndiName = jndiName; } diff --git a/jetty-plus/src/test/java/org/eclipse/jetty/plus/jndi/TestNamingEntries.java b/jetty-plus/src/test/java/org/eclipse/jetty/plus/jndi/TestNamingEntries.java index 7868b14aaf0..760bf288dd5 100644 --- a/jetty-plus/src/test/java/org/eclipse/jetty/plus/jndi/TestNamingEntries.java +++ b/jetty-plus/src/test/java/org/eclipse/jetty/plus/jndi/TestNamingEntries.java @@ -23,6 +23,7 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.util.ArrayList; import java.util.Hashtable; @@ -238,6 +239,35 @@ public class TestNamingEntries testLink(); } + + @Test + public void testNullJndiName () throws Exception + { + try + { + InitialContext icontext = new InitialContext(); + Resource resource = new Resource (null,"foo"); + fail ("Null jndi name should not be permitted"); + } + catch (NamingException e) + { + //expected + } + } + + @Test + public void testNullObject () throws Exception + { + InitialContext icontext = new InitialContext(); + Resource resource = new Resource ("foo/bar", null); + NamingEntry ne = NamingEntryUtil.lookupNamingEntry(null, "foo/bar"); + assertNotNull(ne); + Object o = icontext.lookup("foo/bar"); + assertNull(o); + + } + + @Test public void testLink () throws Exception { 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 c77fbb0cc78..e8e66b2d9e9 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 @@ -1118,7 +1118,6 @@ public class HttpOutput extends ServletOutputStream implements Runnable else { _slice=_buffer.duplicate(); - _buffer.position(_buffer.limit()); } } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpOutputTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpOutputTest.java index 5fe09ef3890..9b91d766cc9 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/HttpOutputTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/HttpOutputTest.java @@ -19,6 +19,7 @@ package org.eclipse.jetty.server; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.endsWith; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; @@ -140,6 +141,7 @@ public class HttpOutputTest String response=_connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n"); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,Matchers.not(containsString("Content-Length"))); + assertThat(response, endsWith(toUTF8String(big))); } @Test @@ -164,6 +166,7 @@ public class HttpOutputTest assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,containsString("Transfer-Encoding: chunked")); + assertThat(response, containsString("1\tThis is a big file")); assertThat(response,containsString("400\tThis is a big file")); assertThat(response,containsString("\r\n0\r\n")); @@ -191,7 +194,7 @@ public class HttpOutputTest String response=_connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n"); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,Matchers.not(containsString("Content-Length"))); - assertThat(response,containsString("400\tThis is a big file")); + assertThat(response, endsWith(toUTF8String(big))); } @Test @@ -202,7 +205,7 @@ public class HttpOutputTest String response=_connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n"); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,containsString("Content-Length")); - assertThat(response,containsString("400\tThis is a big file")); + assertThat(response, endsWith(toUTF8String(big))); } @Test @@ -213,7 +216,7 @@ public class HttpOutputTest String response=_connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n"); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,containsString("Content-Length")); - assertThat(response,containsString("400\tThis is a big file")); + assertThat(response, endsWith(toUTF8String(big))); } @@ -261,6 +264,8 @@ public class HttpOutputTest String response = endp.getResponse(); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,containsString("Transfer-Encoding: chunked")); + assertThat(response, containsString("1\tThis is a big file")); + assertThat(response, containsString("400\tThis is a big file")); assertThat(response,containsString("\r\n0\r\n")); response = endp.getResponse(); @@ -279,7 +284,7 @@ public class HttpOutputTest String response=_connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n"); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,Matchers.not(containsString("Content-Length"))); - assertThat(response,containsString("400\tThis is a big file")); + assertThat(response, endsWith(toUTF8String(big))); } @Test @@ -293,7 +298,7 @@ public class HttpOutputTest String response=_connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n"); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,Matchers.not(containsString("Content-Length"))); - assertThat(response,containsString("400\tThis is a big file")); + assertThat(response, endsWith(toUTF8String(big))); } @Test @@ -307,7 +312,7 @@ public class HttpOutputTest String response=_connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n"); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,Matchers.not(containsString("Content-Length"))); - assertThat(response,containsString("400\tThis is a big file")); + assertThat(response, endsWith(toUTF8String(big))); } @Test @@ -321,7 +326,7 @@ public class HttpOutputTest String response=_connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n"); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,Matchers.not(containsString("Content-Length"))); - assertThat(response,containsString("400\tThis is a big file")); + assertThat(response, endsWith(toUTF8String(big))); } @Test @@ -335,7 +340,7 @@ public class HttpOutputTest String response=_connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n"); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,containsString("Content-Length")); - assertThat(response,containsString("400\tThis is a big file")); + assertThat(response, endsWith(toUTF8String(big))); } @Test @@ -349,7 +354,7 @@ public class HttpOutputTest String response=_connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n"); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,containsString("Content-Length")); - assertThat(response,containsString("400\tThis is a big file")); + assertThat(response, endsWith(toUTF8String(big))); } @Test @@ -363,7 +368,7 @@ public class HttpOutputTest String response=_connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n"); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,containsString("Content-Length")); - assertThat(response,containsString("400\tThis is a big file")); + assertThat(response, endsWith(toUTF8String(big))); } @Test @@ -377,7 +382,7 @@ public class HttpOutputTest String response=_connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n"); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,containsString("Content-Length")); - assertThat(response,containsString("400\tThis is a big file")); + assertThat(response, endsWith(toUTF8String(big))); } @@ -408,7 +413,7 @@ public class HttpOutputTest String response=_connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n"); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,Matchers.not(containsString("Content-Length"))); - assertThat(response,containsString("400\tThis is a big file")); + assertThat(response, endsWith(toUTF8String(big))); } @Test @@ -422,7 +427,7 @@ public class HttpOutputTest String response=_connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n"); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,Matchers.not(containsString("Content-Length"))); - assertThat(response,containsString("400\tThis is a big file")); + assertThat(response, endsWith(toUTF8String(big))); } @Test @@ -436,7 +441,7 @@ public class HttpOutputTest String response=_connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n"); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,Matchers.not(containsString("Content-Length"))); - assertThat(response,containsString("400\tThis is a big file")); + assertThat(response, endsWith(toUTF8String(big))); } @@ -452,7 +457,7 @@ public class HttpOutputTest String response=_connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n"); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,Matchers.not(containsString("Content-Length"))); - assertThat(response,containsString("400\tThis is a big file")); + assertThat(response, endsWith(toUTF8String(big))); } @Test @@ -467,7 +472,7 @@ public class HttpOutputTest String response=_connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n"); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,Matchers.not(containsString("Content-Length"))); - assertThat(response,containsString("400\tThis is a big file")); + assertThat(response, endsWith(toUTF8String(big))); } @Test @@ -482,7 +487,7 @@ public class HttpOutputTest String response=_connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n"); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,Matchers.not(containsString("Content-Length"))); - assertThat(response,containsString("400\tThis is a big file")); + assertThat(response, endsWith(toUTF8String(big))); } @Test @@ -497,7 +502,7 @@ public class HttpOutputTest String response=_connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n"); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,Matchers.not(containsString("Content-Length"))); - assertThat(response,containsString("400\tThis is a big file")); + assertThat(response, endsWith(toUTF8String(big))); } @@ -531,7 +536,7 @@ public class HttpOutputTest String response=_connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n"); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,Matchers.not(containsString("Content-Length"))); - assertThat(response,containsString("400\tThis is a big file")); + assertThat(response, endsWith(toUTF8String(big))); } @Test @@ -546,7 +551,7 @@ public class HttpOutputTest String response=_connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n"); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,Matchers.not(containsString("Content-Length"))); - assertThat(response,containsString("400\tThis is a big file")); + assertThat(response, endsWith(toUTF8String(big))); } @Test @@ -561,7 +566,23 @@ public class HttpOutputTest String response=_connector.getResponse("GET / HTTP/1.0\nHost: localhost:80\n\n"); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,Matchers.not(containsString("Content-Length"))); - assertThat(response,containsString("400\tThis is a big file")); + assertThat(response, endsWith(toUTF8String(big))); + } + + @Test + public void testAsyncWriteBufferLargeDirect() + throws Exception + { + final Resource big = Resource.newClassPathResource("simple/big.txt"); + _handler._writeLengthIfKnown = false; + _handler._content = BufferUtil.toBuffer(big, true); + _handler._byteBuffer = BufferUtil.allocateDirect(8192); + _handler._async = true; + + String response = _connector.getResponses("GET / HTTP/1.0\nHost: localhost:80\n\n"); + assertThat(response, containsString("HTTP/1.1 200 OK")); + assertThat(response, Matchers.not(containsString("Content-Length"))); + assertThat(response, endsWith(toUTF8String(big))); } @Test @@ -578,7 +599,8 @@ public class HttpOutputTest assertThat(_handler._owp.get()-start,Matchers.greaterThan(0)); assertThat(response,containsString("HTTP/1.1 200 OK")); assertThat(response,Matchers.not(containsString("Content-Length"))); - assertThat(response,Matchers.not(containsString("400\tThis is a big file"))); + assertThat(response, Matchers.not(containsString("1\tThis is a big file"))); + assertThat(response, Matchers.not(containsString("400\tThis is a big file"))); } @Test @@ -657,6 +679,12 @@ public class HttpOutputTest assertThat(response,Matchers.not(containsString("Content-Length"))); assertThat(response,containsString("400\tTHIS IS A BIGGER FILE")); } + + private static String toUTF8String(Resource resource) + throws IOException + { + return BufferUtil.toUTF8String(BufferUtil.toBuffer(resource, false)); + } interface ChainedInterceptor extends HttpOutput.Interceptor { @@ -775,6 +803,8 @@ public class HttpOutputTest final AsyncContext async = request.startAsync(); out.setWriteListener(new WriteListener() { + private boolean isFirstWrite = true; + @Override public void onWritePossible() throws IOException { @@ -782,6 +812,7 @@ public class HttpOutputTest while (out.isReady()) { + Assert.assertTrue(isFirstWrite || !_byteBuffer.hasRemaining()); Assert.assertTrue(out.isReady()); if(BufferUtil.isEmpty(_content)) { @@ -793,6 +824,7 @@ public class HttpOutputTest BufferUtil.put(_content,_byteBuffer); BufferUtil.flipToFlush(_byteBuffer,0); out.write(_byteBuffer); + isFirstWrite = false; } } diff --git a/jetty-start/pom.xml b/jetty-start/pom.xml index 87b25aac1e5..d70800f7f99 100644 --- a/jetty-start/pom.xml +++ b/jetty-start/pom.xml @@ -32,41 +32,9 @@ org.eclipse.jetty.start.* - - org.apache.maven.plugins - maven-shade-plugin - - true - false - - - org.eclipse.jetty:jetty-util - - - - - org.eclipse.jetty.util - org.eclipse.jetty.start.util - - - - - - package - - shade - - - - - - org.eclipse.jetty - jetty-util - ${project.version} - org.eclipse.jetty.toolchain jetty-test-helper diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java b/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java index 5224a00525c..d4f59a26716 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/Modules.java @@ -34,8 +34,6 @@ import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.eclipse.jetty.util.TopologicalSort; - /** * Access for all modules declared, as well as what is enabled. */ @@ -205,15 +203,8 @@ public class Modules implements Iterable module.getDepends().forEach(add); module.getOptional().forEach(add); } - try - { - sort.sort(_modules); - } - catch (IllegalStateException e) - { - System.err.println(sort.dump()); - throw e; - } + + sort.sort(_modules); } public List getEnabled() diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/StartLog.java b/jetty-start/src/main/java/org/eclipse/jetty/start/StartLog.java index 1d967793a4a..580ebfbe11c 100644 --- a/jetty-start/src/main/java/org/eclipse/jetty/start/StartLog.java +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/StartLog.java @@ -41,6 +41,7 @@ public class StartLog private final static PrintStream stderr = System.err; private static volatile PrintStream out = System.out; private static volatile PrintStream err = System.err; + private static volatile PrintStream logStream = System.err; private final static StartLog INSTANCE = new StartLog(); public static void debug(String format, Object... args) @@ -74,12 +75,12 @@ public class StartLog public static void log(String type, String msg) { - err.println(type + ": " + msg); + logStream.println(type + ": " + msg); } public static void log(String type, String format, Object... args) { - err.printf(type + ": " + format + "%n",args); + logStream.printf(type + ": " + format + "%n",args); } public static void info(String format, Object... args) @@ -94,7 +95,7 @@ public class StartLog public static void warn(Throwable t) { - t.printStackTrace(err); + t.printStackTrace(logStream); } public static boolean isDebugEnabled() @@ -163,9 +164,10 @@ public class StartLog err.println("StartLog to " + logfile); OutputStream fileout = Files.newOutputStream(startLog,StandardOpenOption.CREATE,StandardOpenOption.APPEND); - PrintStream logger = new PrintStream(fileout); + PrintStream logger = new PrintStream(fileout,true); out=logger; err=logger; + setStream(logger); System.setErr(logger); System.setOut(logger); err.println("StartLog Establishing " + logfile + " on " + new Date()); @@ -189,7 +191,20 @@ public class StartLog err.println("StartLog ended"); stderr.println("StartLog ended"); } + setStream(stderr); System.setErr(stderr); System.setOut(stdout); } + + public static PrintStream getStream() + { + return logStream; + } + + public static PrintStream setStream(PrintStream stream) + { + PrintStream ret = logStream; + logStream = stream; + return ret; + } } diff --git a/jetty-start/src/main/java/org/eclipse/jetty/start/TopologicalSort.java b/jetty-start/src/main/java/org/eclipse/jetty/start/TopologicalSort.java new file mode 100644 index 00000000000..5253657b188 --- /dev/null +++ b/jetty-start/src/main/java/org/eclipse/jetty/start/TopologicalSort.java @@ -0,0 +1,185 @@ +// +// ======================================================================== +// 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.start; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; + +/** + * Topological sort a list or array. + *

A Topological sort is used when you have a partial ordering expressed as + * dependencies between elements (also often represented as edges in a directed + * acyclic graph). A Topological sort should not be used when you have a total + * ordering expressed as a {@link Comparator} over the items. The algorithm has + * the additional characteristic that dependency sets are sorted by the original + * list order so that order is preserved when possible.

+ *

+ * The sort algorithm works by recursively visiting every item, once and + * only once. On each visit, the items dependencies are first visited and then the + * item is added to the sorted list. Thus the algorithm ensures that dependency + * items are always added before dependent items.

+ * + * @param The type to be sorted. It must be able to be added to a {@link HashSet} + */ +@SuppressWarnings("Duplicates") +public class TopologicalSort +{ + private final Map> _dependencies = new HashMap<>(); + + /** + * Add a dependency to be considered in the sort. + * @param dependent The dependent item will be sorted after all its dependencies + * @param dependency The dependency item, will be sorted before its dependent item + */ + public void addDependency(T dependent, T dependency) + { + Set set = _dependencies.get(dependent); + if (set==null) + { + set=new HashSet<>(); + _dependencies.put(dependent,set); + } + set.add(dependency); + } + + /** Sort the passed array according to dependencies previously set with + * {@link #addDependency(Object, Object)}. Where possible, ordering will be + * preserved if no dependency + * @param array The array to be sorted. + */ + public void sort(T[] array) + { + List sorted = new ArrayList<>(); + Set visited = new HashSet<>(); + Comparator comparator = new InitialOrderComparator<>(array); + + // Visit all items in the array + for (T t : array) + visit(t,visited,sorted,comparator); + + sorted.toArray(array); + } + + /** Sort the passed list according to dependencies previously set with + * {@link #addDependency(Object, Object)}. Where possible, ordering will be + * preserved if no dependency + * @param list The list to be sorted. + */ + public void sort(Collection list) + { + List sorted = new ArrayList<>(); + Set visited = new HashSet<>(); + Comparator comparator = new InitialOrderComparator<>(list); + + // Visit all items in the list + for (T t : list) + visit(t,visited,sorted,comparator); + + list.clear(); + list.addAll(sorted); + } + + /** Visit an item to be sorted. + * @param item The item to be visited + * @param visited The Set of items already visited + * @param sorted The list to sort items into + * @param comparator A comparator used to sort dependencies. + */ + private void visit(T item, Set visited, List sorted,Comparator comparator) + { + // If the item has not been visited + if(!visited.contains(item)) + { + // We are visiting it now, so add it to the visited set + visited.add(item); + + // Lookup the items dependencies + Set dependencies = _dependencies.get(item); + if (dependencies!=null) + { + // Sort the dependencies + SortedSet ordered_deps = new TreeSet<>(comparator); + ordered_deps.addAll(dependencies); + + // recursively visit each dependency + for (T d:ordered_deps) + visit(d,visited,sorted,comparator); + } + + // Now that we have visited all our dependencies, they and their + // dependencies will have been added to the sorted list. So we can + // now add the current item and it will be after its dependencies + sorted.add(item); + } + else if (!sorted.contains(item)) + // If we have already visited an item, but it has not yet been put in the + // sorted list, then we must be in a cycle! + throw new IllegalStateException("cyclic at "+item); + } + + + /** A comparator that is used to sort dependencies in the order they + * were in the original list. This ensures that dependencies are visited + * in the original order and no needless reordering takes place. + * @param + */ + private static class InitialOrderComparator implements Comparator + { + private final Map _indexes = new HashMap<>(); + InitialOrderComparator(T[] initial) + { + int i=0; + for (T t : initial) + _indexes.put(t,i++); + } + + InitialOrderComparator(Collection initial) + { + int i=0; + for (T t : initial) + _indexes.put(t,i++); + } + + @Override + public int compare(T o1, T o2) + { + Integer i1=_indexes.get(o1); + Integer i2=_indexes.get(o2); + if (i1==null || i2==null || i1.equals(o2)) + return 0; + if (i1 expectedXmls = new ArrayList<>(); for (String line : textFile) @@ -89,10 +103,10 @@ public class ConfigurationAssert List actualXmls = new ArrayList<>(); for (Path xml : args.getXmlFiles()) { - actualXmls.add(shorten(baseHome,xml,testResourcesDir)); + actualXmls.add(shorten(baseHome, xml, testResourcesDir)); } - assertOrdered("XML Resolution Order",expectedXmls,actualXmls); - + assertOrdered("XML Resolution Order", expectedXmls, actualXmls); + // Validate LIBs (order is not important) List expectedLibs = new ArrayList<>(); for (String line : textFile) @@ -105,10 +119,10 @@ public class ConfigurationAssert List actualLibs = new ArrayList<>(); for (File path : args.getClasspath()) { - actualLibs.add(shorten(baseHome,path.toPath(),testResourcesDir)); + actualLibs.add(shorten(baseHome, path.toPath(), testResourcesDir)); } - assertContainsUnordered("Libs",expectedLibs,actualLibs); - + assertContainsUnordered("Libs", expectedLibs, actualLibs); + // Validate PROPERTIES (order is not important) Set expectedProperties = new HashSet<>(); for (String line : textFile) @@ -123,16 +137,16 @@ public class ConfigurationAssert { String name = prop.key; if ("jetty.home".equals(name) || "jetty.base".equals(name) || - "user.dir".equals(name) || prop.origin.equals(Props.ORIGIN_SYSPROP) || - name.startsWith("java.")) + "user.dir".equals(name) || prop.origin.equals(Props.ORIGIN_SYSPROP) || + name.startsWith("java.")) { // strip these out from assertion, to make assertions easier. continue; } actualProperties.add(prop.key + "=" + args.getProperties().expand(prop.value)); } - assertContainsUnordered("Properties",expectedProperties,actualProperties); - + assertContainsUnordered("Properties", expectedProperties, actualProperties); + // Validate Downloads List expectedDownloads = new ArrayList<>(); for (String line : textFile) @@ -147,20 +161,34 @@ public class ConfigurationAssert { if (darg.uri != null) { - actualDownloads.add(String.format("%s|%s",darg.uri,darg.location)); + actualDownloads.add(String.format("%s|%s", darg.uri, darg.location)); } } - assertContainsUnordered("Downloads",expectedDownloads,actualDownloads); - - textFile.stream() - .filter(s->s.startsWith("EXISTS|")).map(f->f.substring(7)).forEach(f-> + assertContainsUnordered("Downloads", expectedDownloads, actualDownloads); + + // File / Path Existence Checks + streamOf(textFile, "EXISTS").forEach(f -> { - Path path=baseHome.getBasePath().resolve(f); - assertTrue(baseHome.toShortForm(path)+" exists?",Files.exists(path)); - assertEquals(baseHome.toShortForm(path)+" isDir?",f.endsWith("/"),Files.isDirectory(path)); + Path path = baseHome.getPath(f); + if (f.endsWith("/")) + { + PathAssert.assertDirExists("Required Directory", path); + } + else + { + PathAssert.assertFileExists("Required File", path); + } + }); + + // Output Validation + streamOf(textFile, "OUTPUT").forEach(regex -> + { + Pattern pat = Pattern.compile(regex); + Matcher mat = pat.matcher(output); + assertTrue("Output [\n" + output + "]\nContains Regex Match: " + pat.pattern(), mat.find()); }); } - + private static String shorten(BaseHome baseHome, Path path, Path testResourcesDir) { String value = baseHome.toShortForm(path); @@ -168,7 +196,7 @@ public class ConfigurationAssert { return value; } - + if (path.startsWith(testResourcesDir)) { int len = testResourcesDir.toString().length(); @@ -181,41 +209,47 @@ public class ConfigurationAssert { try { - Assert.assertEquals(msg,expectedSet.size(),actualSet.size()); + Assert.assertEquals(msg, expectedSet.size(), actualSet.size()); if (!expectedSet.isEmpty()) - Assert.assertThat(msg,actualSet,Matchers.containsInAnyOrder(expectedSet.toArray())); + assertThat(msg, actualSet, Matchers.containsInAnyOrder(expectedSet.toArray())); } - catch(AssertionError e) + catch (AssertionError e) { - System.err.println("Expected: "+expectedSet); - System.err.println("Actual : "+actualSet); + System.err.println("Expected: " + expectedSet); + System.err.println("Actual : " + actualSet); throw e; } } - + public static void assertOrdered(String msg, List expectedList, List actualList) { try { - Assert.assertEquals(msg,expectedList.size(),actualList.size()); + Assert.assertEquals(msg, expectedList.size(), actualList.size()); if (!expectedList.isEmpty()) - Assert.assertThat(msg,actualList,Matchers.contains(expectedList.toArray())); + assertThat(msg, actualList, Matchers.contains(expectedList.toArray())); } - catch(AssertionError e) + catch (AssertionError e) { - System.err.println("Expected: "+expectedList); - System.err.println("Actual : "+actualList); + System.err.println("Expected: " + expectedList); + System.err.println("Actual : " + actualList); throw e; } } - + + private static Stream streamOf(TextFile textFile, String key) + { + return textFile.stream() + .filter(s -> s.startsWith(key + "|")).map(f -> getValue(f)); + } + private static String getValue(String arg) { int idx = arg.indexOf('|'); - Assert.assertThat("Expecting '|' sign in [" + arg + "]",idx,greaterThanOrEqualTo(0)); + assertThat("Expecting '|' sign in [" + arg + "]", idx, greaterThanOrEqualTo(0)); String value = arg.substring(idx + 1).trim(); - Assert.assertThat("Expecting Value after '|' in [" + arg + "]",value.length(),greaterThan(0)); + assertThat("Expecting Value after '|' in [" + arg + "]", value.length(), greaterThan(0)); return value; } } diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java b/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java index 799a5a16963..4705f3d3412 100644 --- a/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java +++ b/jetty-start/src/test/java/org/eclipse/jetty/start/MainTest.java @@ -30,7 +30,7 @@ import java.util.List; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.TestTracker; -import org.eclipse.jetty.util.IO; +import org.eclipse.jetty.toolchain.test.IO; import org.junit.Before; import org.junit.Ignore; import org.junit.Rule; diff --git a/jetty-start/src/test/java/org/eclipse/jetty/start/TestUseCases.java b/jetty-start/src/test/java/org/eclipse/jetty/start/TestUseCases.java index 031f52acc1e..8c183e3978a 100644 --- a/jetty-start/src/test/java/org/eclipse/jetty/start/TestUseCases.java +++ b/jetty-start/src/test/java/org/eclipse/jetty/start/TestUseCases.java @@ -20,15 +20,19 @@ package org.eclipse.jetty.start; import static java.util.stream.Collectors.toList; +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FilenameFilter; +import java.io.FileReader; import java.io.IOException; +import java.io.PrintStream; +import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.List; -import org.eclipse.jetty.toolchain.test.IO; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.hamcrest.Matchers; import org.junit.Assert; @@ -46,107 +50,114 @@ public class TestUseCases { @Parameters(name = "{0}") public static List getCases() throws Exception - { + { File usecases = MavenTestingUtils.getTestResourceDir("usecases/"); - File[] cases=usecases.listFiles(new FilenameFilter() - { - @Override - public boolean accept(File dir, String name) - { - return name.endsWith(".assert.txt"); - } - }); - + File[] cases = usecases.listFiles((dir, name) -> name.endsWith(".assert.txt")); Arrays.sort(cases); List ret = new ArrayList<>(); - for(File assertTxt:cases) + for (File assertTxt : cases) { - String caseName=assertTxt.getName().replace(".assert.txt",""); - String baseName=caseName.split("\\.")[0]; - ret.add(new Object[] {caseName,baseName, assertTxt, lines(new File(usecases,caseName+".prepare.txt")),lines(new File(usecases,caseName+".cmdline.txt"))}); + String caseName = assertTxt.getName().replace(".assert.txt", ""); + ret.add(new Object[]{caseName}); } return ret; } - - static String[] lines(File file) throws IOException - { - if (!file.exists() || !file.canRead()) - return new String[0]; - return IO.readToString(file).split("[\n\r]+"); - } @Parameter(0) public String caseName; - @Parameter(1) - public String baseName; - - @Parameter(2) - public File assertFile; - - @Parameter(3) - public String[] prepare; - - @Parameter(4) - public String[] commandLineArgs; - @Test public void testUseCase() throws Exception { + String baseName = caseName.replaceFirst("\\..*$", ""); + File assertFile = MavenTestingUtils.getTestResourceFile("usecases/" + caseName + ".assert.txt"); + Path homeDir = MavenTestingUtils.getTestResourceDir("dist-home").toPath().toRealPath(); Path baseSrcDir = MavenTestingUtils.getTestResourceDir("usecases/" + baseName).toPath().toRealPath(); Path baseDir = MavenTestingUtils.getTargetTestingPath(caseName); - if (baseDir.toFile().exists()) - org.eclipse.jetty.toolchain.test.FS.cleanDirectory(baseDir); - else - baseDir.toFile().mkdirs(); - org.eclipse.jetty.toolchain.test.IO.copyDir(baseSrcDir.toFile(),baseDir.toFile()); + org.eclipse.jetty.toolchain.test.FS.ensureEmpty(baseDir); + org.eclipse.jetty.toolchain.test.IO.copyDir(baseSrcDir.toFile(), baseDir.toFile()); + System.setProperty("jetty.home", homeDir.toString()); + System.setProperty("jetty.base", baseDir.toString()); - System.setProperty("jetty.home",homeDir.toString()); - System.setProperty("jetty.base",baseDir.toString()); - + ByteArrayOutputStream out = new ByteArrayOutputStream(); + PrintStream originalStream = StartLog.setStream(new PrintStream(out)); try { - if (prepare != null && prepare.length>0) + // If there is a "{caseName}.prepare.txt" then use those + // lines as if you are calling start.jar once to setup + // the base directory. + List prepareArgs = lines(caseName + ".prepare.txt"); + if (!prepareArgs.isEmpty()) { - for (String arg : prepare) - { - Main main = new Main(); - List cmdLine = new ArrayList<>(); - cmdLine.add("--testing-mode"); - cmdLine.addAll(Arrays.asList(arg.split(" "))); - main.start(main.processCommandLine(cmdLine)); - } + Main main = new Main(); + List cmdLine = new ArrayList<>(); + cmdLine.add("--testing-mode"); + cmdLine.addAll(prepareArgs); + + main.start(main.processCommandLine(cmdLine)); } - + Main main = new Main(); List cmdLine = new ArrayList<>(); - cmdLine.add("--debug"); - if (commandLineArgs != null) - { - for (String arg : commandLineArgs) - cmdLine.add(arg); - } - + // cmdLine.add("--debug"); + + // If there is a "{caseName}.cmdline.txt" then these + // entries are extra command line argument to use for + // the actual testcase + cmdLine.addAll(lines(caseName + ".cmdline.txt")); StartArgs args = main.processCommandLine(cmdLine); args.getAllModules().checkEnabledModules(); BaseHome baseHome = main.getBaseHome(); - ConfigurationAssert.assertConfiguration(baseHome,args,assertFile); + + StartLog.setStream(originalStream); + String output = out.toString(StandardCharsets.UTF_8.name()); + ConfigurationAssert.assertConfiguration(baseHome, args, output, assertFile); } catch (Exception e) { - List exceptions = Arrays.asList(lines(assertFile)).stream().filter(s->s.startsWith("EX|")).collect(toList()); + List exceptions = lines(assertFile).stream().filter(s -> s.startsWith("EX|")).collect(toList()); if (exceptions.isEmpty()) throw e; - for (String ex:exceptions) + for (String ex : exceptions) { - ex=ex.substring(3); - Assert.assertThat(e.toString(),Matchers.containsString(ex)); + ex = ex.substring(3); + Assert.assertThat(e.toString(), Matchers.containsString(ex)); } } + finally + { + StartLog.setStream(originalStream); + } + } + + private List lines(String filename) throws IOException + { + return lines(MavenTestingUtils.getTestResourcesPath().resolve("usecases" + File.separator + filename).toFile()); + } + + private List lines(File file) throws IOException + { + if (!file.exists() || !file.canRead()) + return Collections.emptyList(); + List ret = new ArrayList<>(); + try (FileReader reader = new FileReader(file); + BufferedReader buf = new BufferedReader(reader)) + { + String line; + while ((line = buf.readLine()) != null) + { + line = line.trim(); + if (line.length() > 0) + { + ret.add(line); + } + } + } + return ret; } } diff --git a/jetty-start/src/test/resources/usecases/dynamic-loop.0.prepare.txt b/jetty-start/src/test/resources/usecases/dynamic-loop.0.prepare.txt index 99dcff0e0ff..535d63e02ec 100644 --- a/jetty-start/src/test/resources/usecases/dynamic-loop.0.prepare.txt +++ b/jetty-start/src/test/resources/usecases/dynamic-loop.0.prepare.txt @@ -1 +1,2 @@ ---create-startd --add=tom +--create-startd +--add-to-start=tom diff --git a/jetty-start/src/test/resources/usecases/empty.addToStartCreateStartd.assert.txt b/jetty-start/src/test/resources/usecases/empty.addToStartCreateStartd.assert.txt index 0b80f1c57a9..6b2ed3d8921 100644 --- a/jetty-start/src/test/resources/usecases/empty.addToStartCreateStartd.assert.txt +++ b/jetty-start/src/test/resources/usecases/empty.addToStartCreateStartd.assert.txt @@ -19,5 +19,9 @@ PROP|optional.prop=value0 # Files / Directories to create EXISTS|maindir/ -EXISTS|start.d/start.ini +EXISTS|start.d/main.ini +EXISTS|start.d/extra.ini EXISTS|start.d/optional.ini + +# Output Assertions [regex!] (order is irrelevant) +OUTPUT|MKDIR: \$\{jetty.base\}/maindir \ No newline at end of file diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java index 924b2236d71..c29098d49c8 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java @@ -139,7 +139,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL // with a more automatic distributed mechanism public final static String[] __dftServerClasses = { - "-org.eclipse.jetty.session.infinispan.", //don't hide infinispan support classes + "-org.eclipse.jetty.server.session.SessionData", //don't hide SessionData for de/serialization purposes "-org.eclipse.jetty.jmx.", // don't hide jmx classes "-org.eclipse.jetty.util.annotation.", // don't hide jmx annotation "-org.eclipse.jetty.continuation.", // don't hide continuation classes