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.toolchainjetty-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