Merge branch 'master' into release-9
diff --git a/VERSION.txt b/VERSION.txt
index 11204d4..4da151f 100644
--- a/VERSION.txt
+++ b/VERSION.txt
@@ -1,3 +1,6 @@
+jetty-9.0.2-SNAPSHOT
+
+
jetty-9.0.1.v20130408 - 08 April 2013
+ 384552 add comment to jetty-https.xml describing keymanager password
+ 385488 non existing resources in collection are just warnings
diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java
index c8b5f94..92f5ddb 100644
--- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java
+++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/ManyConnectors.java
@@ -67,6 +67,7 @@
new SslConnectionFactory(sslContextFactory,"http/1.1"),
new HttpConnectionFactory(https_config));
https.setPort(8443);
+ https.setIdleTimeout(500000);
// Set the connectors
server.setConnectors(new Connector[] { http, https });
diff --git a/examples/embedded/src/main/resources/jetty-logging.properties b/examples/embedded/src/main/resources/jetty-logging.properties
index f912160..73456ad 100644
--- a/examples/embedded/src/main/resources/jetty-logging.properties
+++ b/examples/embedded/src/main/resources/jetty-logging.properties
@@ -5,5 +5,6 @@
#org.eclipse.jetty.STACKS=false
#org.eclipse.jetty.spdy.LEVEL=DEBUG
#org.eclipse.jetty.server.LEVEL=DEBUG
-#org.eclipse.jetty.io.ssl.LEVEL=DEBUG
+org.eclipse.jetty.io.LEVEL=DEBUG
+org.eclipse.jetty.io.ssl.LEVEL=DEBUG
#org.eclipse.jetty.spdy.server.LEVEL=DEBUG
diff --git a/examples/embedded/src/main/resources/jetty-otherserver.xml b/examples/embedded/src/main/resources/jetty-otherserver.xml
new file mode 100644
index 0000000..04e3358
--- /dev/null
+++ b/examples/embedded/src/main/resources/jetty-otherserver.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
+
+<Configure id="OtherServer" class="org.eclipse.jetty.server.Server">
+ <Set name="handler">
+ <New id="Handlers" class="org.eclipse.jetty.server.handler.HandlerCollection">
+ <Set name="handlers">
+ <Array type="org.eclipse.jetty.server.Handler">
+ <Item>
+ <New id="OtherContexts" class="org.eclipse.jetty.server.handler.ContextHandlerCollection"/>
+ </Item>
+ <Item>
+ <New class="org.eclipse.jetty.server.handler.DefaultHandler"/>
+ </Item>
+ </Array>
+ </Set>
+ </New>
+ </Set>
+
+ <Call name="addConnector">
+ <Arg>
+ <New class="org.eclipse.jetty.server.ServerConnector">
+ <Arg name="server"><Ref refid="OtherServer" /></Arg>
+ <Set name="port">8888</Set>
+ </New>
+ </Arg>
+ </Call>
+
+ <Call name="addBean">
+ <Arg>
+ <New id="DeploymentManager" class="org.eclipse.jetty.deploy.DeploymentManager">
+ <Set name="contexts">
+ <Ref refid="OtherContexts" />
+ </Set>
+
+ <Call id="webappprovider" name="addAppProvider">
+ <Arg>
+ <New class="org.eclipse.jetty.deploy.providers.WebAppProvider">
+ <Set name="monitoredDirName"><Property name="jetty.home" default="." />/other-webapps</Set>
+ <Set name="defaultsDescriptor"><Property name="jetty.home" default="." />/etc/webdefault.xml</Set>
+ <Set name="configurationManager">
+ <New class="org.eclipse.jetty.deploy.PropertiesConfigurationManager"/>
+ </Set>
+ </New>
+ </Arg>
+ </Call>
+ </New>
+ </Arg>
+ </Call>
+</Configure>
diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotation.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotation.java
index f8c4e2b..f76eadf 100644
--- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotation.java
+++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotation.java
@@ -167,7 +167,7 @@
//if not, add it
for (WebInitParam ip:annotation.initParams())
{
- if (metaData.getOrigin(servletName+".servlet.init-param"+ip.name())==Origin.NotSet)
+ if (metaData.getOrigin(servletName+".servlet.init-param."+ip.name())==Origin.NotSet)
{
holder.setInitParameter(ip.name(), ip.value());
metaData.setOrigin(servletName+".servlet.init-param."+ip.name());
diff --git a/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamResponseListener.java b/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamResponseListener.java
index 644326a..6ac55e6 100644
--- a/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamResponseListener.java
+++ b/jetty-client/src/main/java/org/eclipse/jetty/client/util/InputStreamResponseListener.java
@@ -130,28 +130,23 @@
}
@Override
- public void onFailure(Response response, Throwable failure)
- {
- LOG.debug("Queuing failure {} {}", FAILURE, failure);
- queue.offer(FAILURE);
- responseLatch.countDown();
- resultLatch.countDown();
- this.failure = failure;
- signal();
- }
-
- @Override
- public void onSuccess(Response response)
- {
- LOG.debug("Queuing end of content {}{}", EOF, "");
- queue.offer(EOF);
- }
-
- @Override
public void onComplete(Result result)
{
this.result = result;
+ if (result.isSucceeded())
+ {
+ LOG.debug("Queuing end of content {}{}", EOF, "");
+ queue.offer(EOF);
+ }
+ else
+ {
+ LOG.debug("Queuing failure {} {}", FAILURE, failure);
+ queue.offer(FAILURE);
+ this.failure = result.getFailure();
+ responseLatch.countDown();
+ }
resultLatch.countDown();
+ signal();
}
protected boolean await()
@@ -176,7 +171,7 @@
{
synchronized (this)
{
- notify();
+ notifyAll();
}
}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientStreamTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientStreamTest.java
index 218f0e0..5a800af 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientStreamTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/HttpClientStreamTest.java
@@ -445,6 +445,20 @@
Assert.assertNull(failure.get());
}
+ @Test
+ public void testInputStreamResponseListenerFailedBeforeResponse() throws Exception
+ {
+ start(new EmptyServerHandler());
+
+ InputStreamResponseListener listener = new InputStreamResponseListener();
+ // Connect to the wrong port
+ client.newRequest("localhost", 0)
+ .scheme(scheme)
+ .send(listener);
+ Result result = listener.await(5, TimeUnit.SECONDS);
+ Assert.assertNotNull(result);
+ }
+
@Test(expected = ExecutionException.class)
public void testInputStreamContentProviderThrowingWhileReading() throws Exception
{
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesClientTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesClientTest.java
index 67c9931..c7a685c 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesClientTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesClientTest.java
@@ -357,12 +357,7 @@
proxy.flushToClient(record);
record = proxy.readFromClient();
- Assert.assertEquals(TLSRecord.Type.ALERT, record.getType());
- proxy.flushToServer(record);
-
- record = proxy.readFromClient();
Assert.assertNull(record);
- proxy.flushToServer(record);
server.close();
}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesServerTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesServerTest.java
index 1faca02..e0130dd 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesServerTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesServerTest.java
@@ -72,7 +72,6 @@
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
public class SslBytesServerTest extends SslBytesTest
@@ -87,6 +86,7 @@
private SslContextFactory sslContextFactory;
private SSLContext sslContext;
private SimpleProxy proxy;
+ private Runnable idleHook;
@Before
public void init() throws Exception
@@ -119,6 +119,15 @@
}
};
}
+
+ @Override
+ protected boolean onReadTimeout()
+ {
+ final Runnable idleHook = SslBytesServerTest.this.idleHook;
+ if (idleHook != null)
+ idleHook.run();
+ return super.onReadTimeout();
+ }
}, connector, endPoint);
}
};
@@ -165,7 +174,6 @@
}
};
connector.setIdleTimeout(idleTimeout);
-// connector.setPort(5870);
connector.setPort(0);
server.addConnector(connector);
@@ -209,7 +217,7 @@
proxy = new SimpleProxy(threadPool, "localhost", serverPort);
proxy.start();
- logger.debug(":{} <==> :{}", proxy.getPort(), serverPort);
+ logger.info("proxy:{} <==> server:{}", proxy.getPort(), serverPort);
}
@After
@@ -377,13 +385,9 @@
Assert.assertNull(String.valueOf(record), record);
proxy.flushToServer(record);
- // Close Alert
- record = proxy.readFromServer();
- proxy.flushToClient(record);
// Socket close
record = proxy.readFromServer();
Assert.assertNull(String.valueOf(record), record);
- proxy.flushToClient(record);
}
@Test
@@ -669,13 +673,9 @@
Assert.assertNull(String.valueOf(record), record);
proxy.flushToServer(record);
- // Close Alert
- record = proxy.readFromServer();
- proxy.flushToClient(record);
// Socket close
record = proxy.readFromServer();
Assert.assertNull(String.valueOf(record), record);
- proxy.flushToClient(record);
}
@Test
@@ -728,22 +728,15 @@
Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType());
proxy.flushToClient(record);
- // Close Alert
+ // Socket close
record = proxy.readFromServer();
- Assert.assertNotNull(record);
- Assert.assertEquals(TLSRecord.Type.ALERT, record.getType());
- // We can't forward to the client, its socket is already closed
+ Assert.assertNull(record);
// Check that we did not spin
TimeUnit.MILLISECONDS.sleep(500);
Assert.assertThat(sslFills.get(), Matchers.lessThan(20));
Assert.assertThat(sslFlushes.get(), Matchers.lessThan(20));
Assert.assertThat(httpParses.get(), Matchers.lessThan(20));
-
- // Socket close
- record = proxy.readFromServer();
- Assert.assertNull(String.valueOf(record), record);
- proxy.flushToClient(record);
}
@Test
@@ -803,11 +796,9 @@
Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType());
proxy.flushToClient(record);
- // Close Alert
+ // Socket close
record = proxy.readFromServer();
- Assert.assertNotNull(record);
- Assert.assertEquals(TLSRecord.Type.ALERT, record.getType());
- // We can't forward to the client, its socket is already closed
+ Assert.assertNull(String.valueOf(record), record);
// Check that we did not spin
TimeUnit.MILLISECONDS.sleep(500);
@@ -819,11 +810,6 @@
record = proxy.readFromClient();
Assert.assertNull(String.valueOf(record), record);
proxy.flushToServer(record);
-
- // Socket close
- record = proxy.readFromServer();
- Assert.assertNull(String.valueOf(record), record);
- proxy.flushToClient(record);
}
@Test
@@ -864,12 +850,9 @@
// Close the raw socket, this generates a truncation attack
proxy.flushToServer(null);
- // Expect alert + raw close from server
- record = proxy.readFromServer();
- Assert.assertEquals(TLSRecord.Type.ALERT, record.getType());
+ // Expect raw close from server
record = proxy.readFromServer();
Assert.assertNull(String.valueOf(record), record);
- proxy.flushToClient(record);
// Check that we did not spin
TimeUnit.MILLISECONDS.sleep(500);
@@ -917,12 +900,9 @@
Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType());
proxy.flushToClient(record);
- // Expect alert + raw close from server
- record = proxy.readFromServer();
- Assert.assertEquals(TLSRecord.Type.ALERT, record.getType());
+ // Expect raw close from server
record = proxy.readFromServer();
Assert.assertNull(String.valueOf(record), record);
- proxy.flushToClient(record);
// Check that we did not spin
TimeUnit.MILLISECONDS.sleep(500);
@@ -1099,6 +1079,7 @@
System.arraycopy(closeBytes, 0, bytes, dataBytes.length, closeBytes.length / 2);
proxy.flushToServer(100, bytes);
+ // Send the other half of the close alert bytes
bytes = new byte[closeBytes.length - closeBytes.length / 2];
System.arraycopy(closeBytes, closeBytes.length / 2, bytes, 0, bytes.length);
proxy.flushToServer(100, bytes);
@@ -1113,27 +1094,15 @@
Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType());
proxy.flushToClient(record);
- // Close Alert
+ // Socket close
record = proxy.readFromServer();
- Assert.assertNotNull(record);
- Assert.assertEquals(TLSRecord.Type.ALERT, record.getType());
- // We can't forward to the client, its socket is already closed
+ Assert.assertNull(record);
// Check that we did not spin
TimeUnit.MILLISECONDS.sleep(500);
Assert.assertThat(sslFills.get(), Matchers.lessThan(20));
Assert.assertThat(sslFlushes.get(), Matchers.lessThan(20));
Assert.assertThat(httpParses.get(), Matchers.lessThan(20));
-
- // Socket close
- record = proxy.readFromClient();
- Assert.assertNull(String.valueOf(record), record);
- proxy.flushToServer(record);
-
- // Socket close
- record = proxy.readFromServer();
- Assert.assertNull(String.valueOf(record), record);
- proxy.flushToClient(record);
}
@Test
@@ -1749,13 +1718,37 @@
client.close();
}
- @Ignore
@Test
public void testRequestConcurrentWithIdleExpiration() throws Exception
{
final SSLSocket client = newClient();
+ final OutputStream clientOutput = client.getOutputStream();
final CountDownLatch latch = new CountDownLatch(1);
+ idleHook = new Runnable()
+ {
+ public void run()
+ {
+ if (latch.getCount()==0)
+ return;
+ try
+ {
+ // Send request
+ clientOutput.write(("" +
+ "GET / HTTP/1.1\r\n" +
+ "Host: localhost\r\n" +
+ "\r\n").getBytes("UTF-8"));
+ clientOutput.flush();
+ latch.countDown();
+ }
+ catch (Exception x)
+ {
+ // Latch won't trigger and test will fail
+ x.printStackTrace();
+ }
+ }
+ };
+
SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow();
client.startHandshake();
Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
@@ -1779,86 +1772,13 @@
Assert.assertThat(sslFlushes.get(), Matchers.lessThan(20));
Assert.assertThat(httpParses.get(), Matchers.lessThan(50));
- completeClose(client);
+ record = proxy.readFromServer();
+ Assert.assertNull(record);
TimeUnit.MILLISECONDS.sleep(200);
- //System.err.println(((Dumpable)server.getConnectors()[0]).dump());
Assert.assertThat(((Dumpable)server.getConnectors()[0]).dump(), Matchers.not(Matchers.containsString("SCEP@")));
-
}
- /*
- @Test
- public void testRequestWriteBlockedWithPipelinedRequest() throws Exception
- {
- final SSLSocket client = newClient();
- final OutputStream clientOutput = client.getOutputStream();
-
- SimpleProxy.AutomaticFlow automaticProxyFlow = proxy.startAutomaticFlow();
- client.startHandshake();
- Assert.assertTrue(automaticProxyFlow.stop(5, TimeUnit.SECONDS));
-
- byte[] data = new byte[128 * 1024];
- Arrays.fill(data, (byte)'X');
- final String content = new String(data, "UTF-8");
- Future<Object> request = threadPool.submit(new Callable<Object>()
- {
- public Object call() throws Exception
- {
- clientOutput.write(("" +
- "POST /echo HTTP/1.1\r\n" +
- "Host: localhost\r\n" +
- "Content-Length: " + content.length() + "\r\n" +
- "\r\n" +
- content).getBytes("UTF-8"));
- clientOutput.flush();
- return null;
- }
- });
-
- // Nine TLSRecords will be generated for the request
- for (int i = 0; i < 9; ++i)
- {
- // Application data
- TLSRecord record = proxy.readFromClient();
- Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType());
- proxy.flushToServer(record, 0);
- }
- Assert.assertNull(request.get(5, TimeUnit.SECONDS));
-
- // We do not read the big request to cause a write blocked on the server
- TimeUnit.MILLISECONDS.sleep(500);
-
- // Now send the pipelined request
- Future<Object> pipelined = threadPool.submit(new Callable<Object>()
- {
- public Object call() throws Exception
- {
- clientOutput.write(("" +
- "GET /pipelined HTTP/1.1\r\n" +
- "Host: localhost\r\n" +
- "\r\n").getBytes("UTF-8"));
- clientOutput.flush();
- return null;
- }
- });
-
- TLSRecord record = proxy.readFromClient();
- Assert.assertEquals(TLSRecord.Type.APPLICATION, record.getType());
- proxy.flushToServer(record, 0);
- Assert.assertNull(pipelined.get(5, TimeUnit.SECONDS));
-
- // Check that we did not spin
- TimeUnit.MILLISECONDS.sleep(500);
- Assert.assertThat(sslFills.get(), lessThan(20));
- Assert.assertThat(sslFlushes.get(), lessThan(20));
- Assert.assertThat(httpParses.get(), lessThan(50));
-
- Thread.sleep(5000);
-
- // closeClient(client);
- }
- */
private void assumeJavaVersionSupportsTLSRenegotiations()
{
// Due to a security bug, TLS renegotiations were disabled in JDK 1.6.0_19-21
@@ -1893,31 +1813,8 @@
Assert.assertNull(String.valueOf(record), record);
proxy.flushToServer(record);
- // Close Alert
- record = proxy.readFromServer();
- proxy.flushToClient(record);
-
// Socket close
record = proxy.readFromServer();
Assert.assertNull(String.valueOf(record), record);
- proxy.flushToClient(record);
- }
-
- private void completeClose(SSLSocket client) throws Exception
- {
- client.close();
-
- // Close Alert
- TLSRecord record = proxy.readFromClient();
- proxy.flushToServer(record);
- // Socket close
- record = proxy.readFromClient();
- Assert.assertNull(String.valueOf(record), record);
- proxy.flushToServer(record);
-
- // Close Alert
- record = proxy.readFromServer();
- proxy.flushToClient(record);
-
}
}
diff --git a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesTest.java b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesTest.java
index c7fe744..b0f5769 100644
--- a/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesTest.java
+++ b/jetty-client/src/test/java/org/eclipse/jetty/client/ssl/SslBytesTest.java
@@ -34,12 +34,17 @@
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+import org.eclipse.jetty.toolchain.test.TestTracker;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.junit.Assert;
+import org.junit.Rule;
public abstract class SslBytesTest
{
+ @Rule
+ public TestTracker tracker = new TestTracker();
+
protected final Logger logger = Log.getLogger(getClass());
public static class TLSRecord
@@ -115,8 +120,7 @@
public void start() throws Exception
{
- serverSocket = new ServerSocket(47009);
-// serverSocket = new ServerSocket(0);
+ serverSocket = new ServerSocket(0);
Thread acceptor = new Thread(this);
acceptor.start();
server = new Socket(serverHost, serverPort);
diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java
index 4fca18f..19b6548 100644
--- a/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java
+++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ssl/SslConnection.java
@@ -190,6 +190,10 @@
if (DEBUG)
LOG.debug("onFillable enter {}", getEndPoint());
+ // We have received a close handshake, close the end point to send FIN.
+ if (_decryptedEndPoint.isInputShutdown())
+ getEndPoint().close();
+
// wake up whoever is doing the fill or the flush so they can
// do all the filling, unwrapping, wrapping and flushing
_decryptedEndPoint.getFillInterest().fillable();
@@ -612,8 +616,11 @@
// maybe we will fill some more on a retry
continue;
}
- // we need to wait for more net data
- return 0;
+ else
+ {
+ // we need to wait for more net data
+ return 0;
+ }
case FINISHED:
throw new IllegalStateException();
@@ -726,6 +733,7 @@
{
_cannotAcceptMoreAppDataToFlush = true;
getEndPoint().flush(_encryptedOutput);
+ getEndPoint().shutdownOutput();
// If we failed to flush the close handshake then we will just pretend that
// the write has progressed normally and let a subsequent call to flush
// (or WriteFlusher#onIncompleteFlushed) to finish writing the close handshake.
@@ -733,8 +741,11 @@
if (BufferUtil.hasContent(_encryptedOutput))
return false;
}
-
// otherwise we have written, and the caller will close the underlying connection
+ else
+ {
+ getEndPoint().shutdownOutput();
+ }
return allConsumed;
case BUFFER_UNDERFLOW:
@@ -823,24 +834,37 @@
{
_bufferPool.release(_encryptedOutput);
_encryptedOutput = null;
- if (_sslEngine.isOutboundDone())
- getEndPoint().shutdownOutput();
}
}
@Override
public void shutdownOutput()
{
- _sslEngine.closeOutbound();
- try
+ boolean ishut = isInputShutdown();
+ if (DEBUG)
+ LOG.debug("{} shutdownOutput: oshut={}, ishut={}", SslConnection.this, isOutputShutdown(), ishut);
+ if (ishut)
{
- flush(BufferUtil.EMPTY_BUFFER);
- }
- catch (IOException e)
- {
- LOG.ignore(e);
+ // Aggressively close, since inbound close alert has already been processed
+ // and the TLS specification allows to close the connection directly, which
+ // is what most other implementations expect: a FIN rather than a TLS close
+ // reply. If a TLS close reply is sent, most implementation send a RST.
getEndPoint().close();
}
+ else
+ {
+ try
+ {
+ _sslEngine.closeOutbound();
+ flush(BufferUtil.EMPTY_BUFFER); // Send close handshake
+ SslConnection.this.fillInterested(); // seek reply FIN or RST or close handshake
+ }
+ catch (Exception e)
+ {
+ LOG.ignore(e);
+ getEndPoint().close();
+ }
+ }
}
@Override
diff --git a/jetty-io/src/test/java/org/eclipse/jetty/io/SelectChannelEndPointSslTest.java b/jetty-io/src/test/java/org/eclipse/jetty/io/SelectChannelEndPointSslTest.java
index 77aea8b..7bd0596 100644
--- a/jetty-io/src/test/java/org/eclipse/jetty/io/SelectChannelEndPointSslTest.java
+++ b/jetty-io/src/test/java/org/eclipse/jetty/io/SelectChannelEndPointSslTest.java
@@ -202,16 +202,21 @@
filled=client.read(sslIn);
if (debug) System.err.println("in="+filled);
- sslIn.flip();
- try
+
+ if (filled>=0)
{
- // Since the client closed abruptly, the server is sending a close alert with a failure
- engine.unwrap(sslIn, appIn);
- Assert.fail();
- }
- catch (SSLException x)
- {
- // Expected
+ // this is the old behaviour.
+ sslIn.flip();
+ try
+ {
+ // Since the client closed abruptly, the server is sending a close alert with a failure
+ engine.unwrap(sslIn, appIn);
+ Assert.fail();
+ }
+ catch (SSLException x)
+ {
+ // Expected
+ }
}
sslIn.clear();
diff --git a/jetty-npn/pom.xml b/jetty-npn/pom.xml
deleted file mode 100644
index 28d3ad1..0000000
--- a/jetty-npn/pom.xml
+++ /dev/null
@@ -1,73 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <parent>
- <groupId>org.eclipse.jetty</groupId>
- <artifactId>jetty-project</artifactId>
- <version>9.0.0-SNAPSHOT</version>
- </parent>
-
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.eclipse.jetty.npn</groupId>
- <artifactId>npn-api</artifactId>
- <version>1.1.1-SNAPSHOT</version>
- <name>Jetty :: Next Protocol Negotiation :: API</name>
-
- <properties>
- <!-- for now we do make it an OSGi bundle...
- but it needs to be in the bootstrap classes at runtime. -->
- <bundle-symbolic-name>org.eclipse.jetty.npn</bundle-symbolic-name>
- </properties>
-
- <scm>
- <connection>scm:git:http://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project.git</connection>
- <developerConnection>scm:git:ssh://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project.git</developerConnection>
- <url>http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/jetty-npn</url>
- </scm>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <extensions>true</extensions>
- <executions>
- <execution>
- <goals>
- <goal>manifest</goal>
- </goals>
- <configuration>
- <instructions>
- <Export-Package>org.eclipse.jetty.npn.*;version="9.0"</Export-Package>
- <Import-Package>*</Import-Package>
- <Bundle-Description>Next Protocol Negotiation API. must be in the bootstrap packages at runtime.</Bundle-Description>
- </instructions>
- </configuration>
- </execution>
- </executions>
- </plugin>
- <plugin>
- <!--
- Required for OSGI
- -->
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <configuration>
- <archive>
- <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
- </archive>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-release-plugin</artifactId>
- <version>2.2.1</version>
- <configuration>
- <useReleaseProfile>false</useReleaseProfile>
- <goals>deploy</goals>
- <arguments>-Peclipse-release</arguments>
- <preparationGoals>clean install</preparationGoals>
- </configuration>
- </plugin>
- </plugins>
- </build>
-</project>
diff --git a/jetty-npn/src/main/java/org/eclipse/jetty/npn/NextProtoNego.java b/jetty-npn/src/main/java/org/eclipse/jetty/npn/NextProtoNego.java
deleted file mode 100644
index 6dbea16..0000000
--- a/jetty-npn/src/main/java/org/eclipse/jetty/npn/NextProtoNego.java
+++ /dev/null
@@ -1,248 +0,0 @@
-//
-// ========================================================================
-// Copyright (c) 1995-2013 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.npn;
-
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.WeakHashMap;
-import javax.net.ssl.SSLEngine;
-import javax.net.ssl.SSLSocket;
-
-/**
- * <p>{@link NextProtoNego} provides an API to applications that want to make use of the
- * <a href="http://technotes.googlecode.com/git/nextprotoneg.html">Next Protocol Negotiation</a>.</p>
- * <p>The NPN extension is only available when using the TLS protocol, therefore applications must
- * ensure that the TLS protocol is used:</p>
- * <pre>
- * SSLContext context = SSLContext.getInstance("TLSv1");
- * </pre>
- * <p>Refer to the
- * <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#SSLContext">list
- * of standard SSLContext protocol names</a> for further information on TLS protocol versions supported.</p>
- * <p>Applications must register instances of either {@link SSLSocket} or {@link SSLEngine} with a
- * {@link ClientProvider} or with a {@link ServerProvider}, depending whether they are on client or
- * server side.</p>
- * <p>The NPN implementation will invoke the provider callbacks to allow applications to interact
- * with the negotiation of the next protocol.</p>
- * <p>Client side typical usage:</p>
- * <pre>
- * SSLSocket sslSocket = ...;
- * NextProtoNego.put(sslSocket, new NextProtoNego.ClientProvider()
- * {
- * @Override
- * public boolean supports()
- * {
- * return true;
- * }
- *
- * @Override
- * public void unsupported()
- * {
- * }
- *
- * @Override
- * public String selectProtocol(List<String> protocols)
- * {
- * return protocols.get(0);
- * }
- * });
- * </pre>
- * <p>Server side typical usage:</p>
- * <pre>
- * SSLSocket sslSocket = ...;
- * NextProtoNego.put(sslSocket, new NextProtoNego.ServerProvider()
- * {
- * @Override
- * public void unsupported()
- * {
- * }
- *
- * @Override
- * public List<String> protocols()
- * {
- * return Arrays.asList("http/1.1");
- * }
- *
- * @Override
- * public void protocolSelected(String protocol)
- * {
- * System.out.println("Protocol Selected is: " + protocol);
- * }
- * });
- * </pre>
- * <p>There is no need to unregister {@link SSLSocket} or {@link SSLEngine} instances, as they
- * are kept in a {@link WeakHashMap} and will be garbage collected when the application does not
- * hard reference them anymore. However, methods to explicitly unregister {@link SSLSocket} or
- * {@link SSLEngine} instances are provided.</p>
- * <p>In order to help application development, you can set the {@link NextProtoNego#debug} field
- * to {@code true} to have debug code printed to {@link System#err}.</p>
- */
-public class NextProtoNego
-{
- /**
- * <p>Enables debug logging on {@link System#err}.</p>
- */
- public static boolean debug = false;
-
- private static Map<Object, Provider> objects = Collections.synchronizedMap(new WeakHashMap<Object, Provider>());
-
- private NextProtoNego()
- {
- }
-
- /**
- * <p>Registers a SSLSocket with a provider.</p>
- *
- * @param socket the socket to register with the provider
- * @param provider the provider to register with the socket
- * @see #remove(SSLSocket)
- */
- public static void put(SSLSocket socket, Provider provider)
- {
- objects.put(socket, provider);
- }
-
- /**
- * @param socket a socket registered with {@link #put(SSLSocket, Provider)}
- * @return the provider registered with the given socket
- */
- public static Provider get(SSLSocket socket)
- {
- return objects.get(socket);
- }
-
- /**
- * <p>Unregisters the given SSLSocket.</p>
- *
- * @param socket the socket to unregister
- * @return the provider registered with the socket
- * @see #put(SSLSocket, Provider)
- */
- public static Provider remove(SSLSocket socket)
- {
- return objects.remove(socket);
- }
-
- /**
- * <p>Registers a SSLEngine with a provider.</p>
- *
- * @param engine the engine to register with the provider
- * @param provider the provider to register with the engine
- * @see #remove(SSLEngine)
- */
- public static void put(SSLEngine engine, Provider provider)
- {
- objects.put(engine, provider);
- }
-
- /**
- *
- * @param engine an engine registered with {@link #put(SSLEngine, Provider)}
- * @return the provider registered with the given engine
- */
- public static Provider get(SSLEngine engine)
- {
- return objects.get(engine);
- }
-
- /**
- * <p>Unregisters the given SSLEngine.</p>
- *
- * @param engine the engine to unregister
- * @return the provider registered with the engine
- * @see #put(SSLEngine, Provider)
- */
- public static Provider remove(SSLEngine engine)
- {
- return objects.remove(engine);
- }
-
- /**
- * <p>Base, empty, interface for providers.</p>
- */
- public interface Provider
- {
- }
-
- /**
- * <p>The client-side provider interface that applications must implement to interact
- * with the negotiation of the next protocol.</p>
- */
- public interface ClientProvider extends Provider
- {
- /**
- * <p>Callback invoked to let the implementation know whether an
- * empty NPN extension should be added to a ClientHello SSL message.</p>
- *
- * @return true to add the NPN extension, false otherwise
- */
- public boolean supports();
-
- /**
- * <p>Callback invoked to let the application know that the server does
- * not support NPN.</p>
- */
- public void unsupported();
-
- /**
- * <p>Callback invoked to let the application select a protocol
- * among the ones sent by the server.</p>
- *
- * @param protocols the protocols sent by the server
- * @return the protocol selected by the application, or null if the
- * NextProtocol SSL message should not be sent to the server
- */
- public String selectProtocol(List<String> protocols);
- }
-
- /**
- * <p>The server-side provider interface that applications must implement to interact
- * with the negotiation of the next protocol.</p>
- */
- public interface ServerProvider extends Provider
- {
- /**
- * <p>Callback invoked to let the application know that the client does not
- * support NPN.</p>
- */
- public void unsupported();
-
- /**
- * <p>Callback invoked to let the implementation know the list
- * of protocols that should be added to an NPN extension in a
- * ServerHello SSL message.</p>
- * <p>This callback is invoked only if the client sent a NPN extension.</p>
- *
- * @return the list of protocols, or null if no NPN extension
- * should be sent to the client
- */
- public List<String> protocols();
-
- /**
- * <p>Callback invoked to let the application know the protocol selected
- * by the client.</p>
- * <p>This callback is invoked only if the client sent a NextProtocol SSL message.</p>
- *
- * @param protocol the selected protocol
- */
- public void protocolSelected(String protocol);
- }
-}
diff --git a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/ContainerTldBundleDiscoverer.java b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/ContainerTldBundleDiscoverer.java
new file mode 100644
index 0000000..f9c212a
--- /dev/null
+++ b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/ContainerTldBundleDiscoverer.java
@@ -0,0 +1,153 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2013 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.osgi.boot.jasper;
+
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.regex.Pattern;
+
+import org.eclipse.jetty.deploy.DeploymentManager;
+import org.eclipse.jetty.osgi.boot.OSGiWebInfConfiguration;
+import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
+import org.eclipse.jetty.osgi.boot.utils.TldBundleDiscoverer;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.FrameworkUtil;
+
+
+
+/**
+ * ContainerTldBundleDiscoverer
+ *
+ *
+ * Use a System property to define bundles that contain tlds that need to
+ * be treated by jasper as if they were on the jetty container's classpath.
+ *
+ * The value of the property is evaluated against the DeploymentManager
+ * context attribute "org.eclipse.jetty.server.webapp.containerIncludeBundlePattern",
+ * which defines a pattern of matching bundle names.
+ *
+ * The bundle locations are converted to URLs for jasper's use.
+ *
+ * Eg:
+ * -Dorg.eclipse.jetty.osgi.tldbundles=org.springframework.web.servlet,com.opensymphony.module.sitemesh
+ *
+ */
+public class ContainerTldBundleDiscoverer implements TldBundleDiscoverer
+{
+ /**
+ * Comma separated list of names of bundles that contain tld files that should be
+ * discoved by jasper as if they were on the container's classpath.
+ * Eg:
+ * -Djetty.osgi.tldbundles=org.springframework.web.servlet,com.opensymphony.module.sitemesh
+ */
+ public static final String SYS_PROP_TLD_BUNDLES = "org.eclipse.jetty.osgi.tldbundles";
+
+
+
+ /**
+ * Check the System property "org.eclipse.jetty.osgi.tldbundles" for names of
+ * bundles that contain tlds and convert to URLs.
+ *
+ * @return The location of the jars that contain tld files as URLs.
+ */
+ public URL[] getUrlsForBundlesWithTlds(DeploymentManager deploymentManager, BundleFileLocatorHelper locatorHelper) throws Exception
+ {
+ // naive way of finding those bundles.
+ // lots of assumptions: for example we assume a single version of each
+ // bundle that would contain tld files.
+ // this is probably good enough as those tlds are loaded system-wide on
+ // jetty.
+ // to do better than this we need to do it on a per webapp basis.
+ // probably using custom properties in the ContextHandler service
+ // and mirroring those in the MANIFEST.MF
+
+ Bundle[] bundles = FrameworkUtil.getBundle(ContainerTldBundleDiscoverer.class).getBundleContext().getBundles();
+ HashSet<URL> urls = new HashSet<URL>();
+ String tmp = System.getProperty(SYS_PROP_TLD_BUNDLES); //comma separated exact names
+ List<String> sysNames = new ArrayList<String>();
+ if (tmp != null)
+ {
+ StringTokenizer tokenizer = new StringTokenizer(tmp, ", \n\r\t", false);
+ while (tokenizer.hasMoreTokens())
+ sysNames.add(tokenizer.nextToken());
+ }
+ tmp = (String) deploymentManager.getContextAttribute(OSGiWebInfConfiguration.CONTAINER_BUNDLE_PATTERN); //bundle name patterns
+ Pattern pattern = (tmp==null? null : Pattern.compile(tmp));
+ for (Bundle bundle : bundles)
+ {
+ if (sysNames.contains(bundle.getSymbolicName()))
+ convertBundleLocationToURL(locatorHelper, bundle, urls);
+
+ if (pattern != null && pattern.matcher(bundle.getSymbolicName()).matches())
+ convertBundleLocationToURL(locatorHelper, bundle, urls);
+ }
+
+ return urls.toArray(new URL[urls.size()]);
+
+ }
+
+ /**
+ * Resolves a bundle that contains tld files as a URL. The URLs are
+ * used by jasper to discover the tld files.
+ *
+ * Support only 2 types of packaging for the bundle: - the bundle is a jar
+ * (recommended for runtime.) - the bundle is a folder and contain jars in
+ * the root and/or in the lib folder (nice for PDE developement situations)
+ * Unsupported: the bundle is a jar that embeds more jars.
+ *
+ * @param locatorHelper
+ * @param bundle
+ * @param urls
+ * @throws Exception
+ */
+ private void convertBundleLocationToURL(BundleFileLocatorHelper locatorHelper, Bundle bundle, Set<URL> urls) throws Exception
+ {
+ File jasperLocation = locatorHelper.getBundleInstallLocation(bundle);
+ if (jasperLocation.isDirectory())
+ {
+ for (File f : jasperLocation.listFiles())
+ {
+ if (f.getName().endsWith(".jar") && f.isFile())
+ {
+ urls.add(f.toURI().toURL());
+ }
+ else if (f.isDirectory() && f.getName().equals("lib"))
+ {
+ for (File f2 : jasperLocation.listFiles())
+ {
+ if (f2.getName().endsWith(".jar") && f2.isFile())
+ {
+ urls.add(f2.toURI().toURL());
+ }
+ }
+ }
+ }
+ urls.add(jasperLocation.toURI().toURL());
+ }
+ else
+ {
+ urls.add(jasperLocation.toURI().toURL());
+ }
+ }
+}
\ No newline at end of file
diff --git a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/WebappRegistrationCustomizerImpl.java b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/JSTLBundleDiscoverer.java
similarity index 94%
rename from jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/WebappRegistrationCustomizerImpl.java
rename to jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/JSTLBundleDiscoverer.java
index 7b744b9..23628c3 100644
--- a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/WebappRegistrationCustomizerImpl.java
+++ b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/JSTLBundleDiscoverer.java
@@ -34,7 +34,7 @@
import org.eclipse.jetty.deploy.DeploymentManager;
import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator;
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
-import org.eclipse.jetty.osgi.boot.utils.WebappRegistrationCustomizer;
+import org.eclipse.jetty.osgi.boot.utils.TldBundleDiscoverer;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.osgi.framework.Bundle;
@@ -44,17 +44,20 @@
import org.xml.sax.SAXException;
/**
+ *
+ * JSTLBundleDiscoverer
+ *
* Fix various shortcomings with the way jasper parses the tld files. Plugs the
* JSTL tlds assuming that they are packaged with the bundle that contains the
* JSTL classes.
* <p>
* Pluggable tlds at the server level are handled by
- * {@link PluggableWebAppRegistrationCustomizerImpl}.
+ * {@link ContainerTldBundleDiscoverer}.
* </p>
*/
-public class WebappRegistrationCustomizerImpl implements WebappRegistrationCustomizer
+public class JSTLBundleDiscoverer implements TldBundleDiscoverer
{
- private static final Logger LOG = Log.getLogger(WebappRegistrationCustomizerImpl.class);
+ private static final Logger LOG = Log.getLogger(JSTLBundleDiscoverer.class);
/**
@@ -83,7 +86,7 @@
*/
private static String DEFAULT_JSP_FACTORY_IMPL_CLASS = "org.apache.jasper.runtime.JspFactoryImpl";
- public WebappRegistrationCustomizerImpl()
+ public JSTLBundleDiscoverer()
{
fixupDtdResolution();
@@ -136,7 +139,7 @@
* @return array of URLs
* @throws Exception
*/
- public URL[] getJarsWithTlds(DeploymentManager deployer, BundleFileLocatorHelper locatorHelper) throws Exception
+ public URL[] getUrlsForBundlesWithTlds(DeploymentManager deployer, BundleFileLocatorHelper locatorHelper) throws Exception
{
ArrayList<URL> urls = new ArrayList<URL>();
@@ -148,7 +151,7 @@
// So we can look for this class using this bundle's classloader:
try
{
- Class<?> jstlClass = WebappRegistrationCustomizerImpl.class.getClassLoader().loadClass(DEFAULT_JSTL_BUNDLE_CLASS);
+ Class<?> jstlClass = JSTLBundleDiscoverer.class.getClassLoader().loadClass(DEFAULT_JSTL_BUNDLE_CLASS);
classesToAddToTheTldBundles.add(jstlClass);
}
diff --git a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/PluggableWebAppRegistrationCustomizerImpl.java b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/PluggableWebAppRegistrationCustomizerImpl.java
deleted file mode 100644
index 2521ed1..0000000
--- a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/PluggableWebAppRegistrationCustomizerImpl.java
+++ /dev/null
@@ -1,187 +0,0 @@
-//
-// ========================================================================
-// Copyright (c) 1995-2013 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.osgi.boot.jasper;
-
-import java.io.File;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.StringTokenizer;
-import java.util.regex.Pattern;
-
-import org.eclipse.jetty.deploy.DeploymentManager;
-import org.eclipse.jetty.osgi.boot.OSGiWebInfConfiguration;
-import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
-import org.eclipse.jetty.osgi.boot.utils.WebappRegistrationCustomizer;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.FrameworkUtil;
-
-/**
- * Plug bundles that contains tld files so that jasper will discover them and
- * set them up in jetty.
- *
- * For example:
- * -Dorg.eclipse.jetty.osgi.tldbundles=org.springframework.web.servlet
- * ,com.opensymphony.module.sitemesh Otherwise use an attribute to the
- * WebAppDeployer <New
- * class="org.eclipse.jetty.deploy.providers.WebAppProvider"> .... <Set
- * name="tldBundles"><Property name="org.eclipse.jetty.osgi.tldsbundles"
- * default="" /></Set> <New>
- */
-public class PluggableWebAppRegistrationCustomizerImpl implements WebappRegistrationCustomizer
-{
- /**
- * To plug into jasper bundles that contain tld files please use a list of
- * bundle's symbolic names:
- * -Djetty.osgi.tldbundles=org.springframework.web.servlet
- * ,com.opensymphony.module.sitemesh
- */
- public static final String SYS_PROP_TLD_BUNDLES = "org.eclipse.jetty.osgi.tldbundles";
-
- /**
- * Union of the tld bundles defined system wide and the one defines as an
- * attribute of the AppProvider.
- *
- * @param provider
- * @return
- */
- private static Collection<String> getTldBundles(DeploymentManager deploymentManager)
- {
- String sysprop = System.getProperty(SYS_PROP_TLD_BUNDLES);
- String att = (String) deploymentManager.getContextAttribute(OSGiWebInfConfiguration.CONTAINER_BUNDLE_PATTERN);
- if (sysprop == null && att == null) { return Collections.emptySet(); }
- if (att == null)
- {
- att = sysprop;
- }
- else if (sysprop != null)
- {
- att = att + "," + sysprop;
- }
-
- Collection<String> tldbundles = new HashSet<String>();
- StringTokenizer tokenizer = new StringTokenizer(att, ", \n\r\t", false);
- while (tokenizer.hasMoreTokens())
- {
- tldbundles.add(tokenizer.nextToken());
- }
- return tldbundles;
- }
-
- /**
- * @return The location of the jars that contain tld files. Jasper will
- * discover them.
- */
- public URL[] getJarsWithTlds(DeploymentManager deploymentManager, BundleFileLocatorHelper locatorHelper) throws Exception
- {
- // naive way of finding those bundles.
- // lots of assumptions: for example we assume a single version of each
- // bundle that would contain tld files.
- // this is probably good enough as those tlds are loaded system-wide on
- // jetty.
- // to do better than this we need to do it on a per webapp basis.
- // probably using custom properties in the ContextHandler service
- // and mirroring those in the MANIFEST.MF
-
- Bundle[] bundles = FrameworkUtil.getBundle(PluggableWebAppRegistrationCustomizerImpl.class).getBundleContext().getBundles();
- HashSet<URL> urls = new HashSet<URL>();
- String tmp = System.getProperty(SYS_PROP_TLD_BUNDLES); //comma separated exact names
- List<String> sysNames = new ArrayList<String>();
- if (tmp != null)
- {
- StringTokenizer tokenizer = new StringTokenizer(tmp, ", \n\r\t", false);
- while (tokenizer.hasMoreTokens())
- sysNames.add(tokenizer.nextToken());
- }
- tmp = (String) deploymentManager.getContextAttribute(OSGiWebInfConfiguration.CONTAINER_BUNDLE_PATTERN); //bundle name patterns
- Pattern pattern = (tmp==null? null : Pattern.compile(tmp));
- for (Bundle bundle : bundles)
- {
- if (sysNames.contains(bundle.getSymbolicName()))
- registerTldBundle(locatorHelper, bundle, urls);
-
- if (pattern != null && pattern.matcher(bundle.getSymbolicName()).matches())
- registerTldBundle(locatorHelper, bundle, urls);
- }
-
- return urls.toArray(new URL[urls.size()]);
-
- }
-
- /**
- * Resolves the bundle that contains tld files as a set of URLs that will be
- * passed to jasper as a URLClassLoader later on. Usually that would be a
- * single URL per bundle. But we do some more work if there are jars
- * embedded in the bundle.
- *
- * The jasper TldScanner expects a URLClassloader to parse a jar for the
- * /META-INF/*.tld it may contain. We place the bundles that we know contain
- * such tag-libraries. Please note that it will work if and only if the
- * bundle is a jar (!) Currently we just hardcode the bundle that contains
- * the jstl implemenation.
- *
- * A workaround when the tld cannot be parsed with this method is to copy
- * and paste it inside the WEB-INF of the webapplication where it is used.
- *
- * Support only 2 types of packaging for the bundle: - the bundle is a jar
- * (recommended for runtime.) - the bundle is a folder and contain jars in
- * the root and/or in the lib folder (nice for PDE developement situations)
- * Unsupported: the bundle is a jar that embeds more jars.
- *
- * @param locatorHelper
- * @param bundle
- * @param urls
- * @throws Exception
- */
- private void registerTldBundle(BundleFileLocatorHelper locatorHelper, Bundle bundle, Set<URL> urls) throws Exception
- {
- File jasperLocation = locatorHelper.getBundleInstallLocation(bundle);
- if (jasperLocation.isDirectory())
- {
- for (File f : jasperLocation.listFiles())
- {
- if (f.getName().endsWith(".jar") && f.isFile())
- {
- urls.add(f.toURI().toURL());
- }
- else if (f.isDirectory() && f.getName().equals("lib"))
- {
- for (File f2 : jasperLocation.listFiles())
- {
- if (f2.getName().endsWith(".jar") && f2.isFile())
- {
- urls.add(f2.toURI().toURL());
- }
- }
- }
- }
- urls.add(jasperLocation.toURI().toURL());
- }
- else
- {
- urls.add(jasperLocation.toURI().toURL());
- }
-
- }
-
-}
\ No newline at end of file
diff --git a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jsp/FragmentActivator.java b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jsp/FragmentActivator.java
index 9741d21..b172702 100644
--- a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jsp/FragmentActivator.java
+++ b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jsp/FragmentActivator.java
@@ -19,21 +19,26 @@
package org.eclipse.jetty.osgi.boot.jsp;
import org.eclipse.jetty.osgi.boot.BundleWebAppProvider;
-import org.eclipse.jetty.osgi.boot.internal.webapp.WebBundleTrackerCustomizer;
-import org.eclipse.jetty.osgi.boot.jasper.PluggableWebAppRegistrationCustomizerImpl;
-import org.eclipse.jetty.osgi.boot.jasper.WebappRegistrationCustomizerImpl;
+import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
+import org.eclipse.jetty.osgi.boot.jasper.ContainerTldBundleDiscoverer;
+import org.eclipse.jetty.osgi.boot.jasper.JSTLBundleDiscoverer;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
/**
- * Pseudo fragment activator. Called by the main org.eclipse.jetty.osgi.boot
- * bundle. Please note: this is not a real BundleActivator. Simply something
- * called back by the host bundle.
- * <p>
- * It must be placed in the org.eclipse.jetty.osgi.boot.jsp package: this is
- * because org.eclipse.jetty.osgi.boot.jsp is the symbolic-name of this
- * fragment. From that name, the PackageadminTracker will call this class. IN a
- * different package it won't be called.
+ * FragmentActivator
+ *
+ * Sets up support for jsp. All relevant jsp jars must also be installed
+ * into the osgi environment.
+ * <p>
+ * Note that as this is part of a bundle fragment, this activator is NOT
+ * called by the OSGi environment. Instead, the org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminTracker
+ * simulates fragment activation and causes this class's start() method to
+ * be called.
+ * </p>
+ * <p>
+ * The package of this class MUST match the Bundle-SymbolicName of this fragment
+ * in order for the PackageAdminTracker to find it.
* </p>
*/
public class FragmentActivator implements BundleActivator
@@ -43,12 +48,14 @@
*/
public void start(BundleContext context) throws Exception
{
+ //jsr199 compilation does not work in osgi
System.setProperty("org.apache.jasper.compiler.disablejsr199", Boolean.TRUE.toString());
- WebBundleTrackerCustomizer.JSP_REGISTRATION_HELPERS.add(new WebappRegistrationCustomizerImpl());
- WebBundleTrackerCustomizer.JSP_REGISTRATION_HELPERS.add(new PluggableWebAppRegistrationCustomizerImpl());
- //Put in the support for the tag libs
- addTagLibSupport();
-
+
+ //set up some classes that will look for bundles with tlds that must be converted
+ //to urls and treated as if they are on the Jetty container's classpath so that
+ //jasper can deal with them
+ ServerInstanceWrapper.addContainerTldBundleDiscoverer(new JSTLBundleDiscoverer());
+ ServerInstanceWrapper.addContainerTldBundleDiscoverer(new ContainerTldBundleDiscoverer());
}
/**
@@ -58,12 +65,4 @@
{
}
-
- public void addTagLibSupport ()
- {
- String[] defaultConfigurations = new String[BundleWebAppProvider.getDefaultConfigurations().length+1];
- System.arraycopy(BundleWebAppProvider.getDefaultConfigurations(), 0, defaultConfigurations, 0, BundleWebAppProvider.getDefaultConfigurations().length);
- defaultConfigurations[defaultConfigurations.length-1] = "org.eclipse.jetty.osgi.boot.jsp.TagLibOSGiConfiguration";
- BundleWebAppProvider.setDefaultConfigurations(defaultConfigurations);
- }
}
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractContextProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractContextProvider.java
index 6f07480..5d801c6 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractContextProvider.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractContextProvider.java
@@ -22,14 +22,12 @@
import java.net.URL;
import java.util.Dictionary;
import java.util.HashMap;
-import java.util.Hashtable;
import org.eclipse.jetty.deploy.App;
import org.eclipse.jetty.deploy.AppProvider;
import org.eclipse.jetty.deploy.DeploymentManager;
import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
import org.eclipse.jetty.osgi.boot.internal.webapp.BundleFileLocatorHelperFactory;
-import org.eclipse.jetty.osgi.boot.utils.EventSender;
import org.eclipse.jetty.osgi.boot.utils.OSGiClassLoader;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
@@ -37,11 +35,8 @@
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.resource.JarResource;
import org.eclipse.jetty.util.resource.Resource;
-import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.xml.XmlConfiguration;
import org.osgi.framework.Bundle;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceRegistration;
@@ -49,14 +44,15 @@
/**
* AbstractContextProvider
*
- *
+ * Base class for DeploymentManager Providers that can deploy ContextHandlers into
+ * Jetty that have been discovered via OSGI either as bundles or services.
+ *
*/
public abstract class AbstractContextProvider extends AbstractLifeCycle implements AppProvider
{
private static final Logger LOG = Log.getLogger(AbstractContextProvider.class);
- private DeploymentManager _deploymentManager;
-
+ private DeploymentManager _deploymentManager;
private ServerInstanceWrapper _serverWrapper;
@@ -65,7 +61,7 @@
/* ------------------------------------------------------------ */
/**
- * BundleApp
+ * OSGiApp
*
*
*/
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractOSGiApp.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractOSGiApp.java
index be09d2c..b9e040b 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractOSGiApp.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractOSGiApp.java
@@ -32,9 +32,10 @@
/**
- * AbstractBundleApp
+ * AbstractOSGiApp
*
- *
+ * Base class representing info about a webapp/ContextHandler that is deployed into Jetty.
+ *
*/
public abstract class AbstractOSGiApp extends App
{
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java
index 73da20f..cbae1c9 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/AbstractWebAppProvider.java
@@ -20,14 +20,9 @@
import java.io.File;
import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
-import java.util.Hashtable;
-import java.util.Map;
-
import org.eclipse.jetty.deploy.App;
import org.eclipse.jetty.deploy.AppProvider;
@@ -35,7 +30,6 @@
import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
import org.eclipse.jetty.osgi.boot.internal.webapp.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.osgi.boot.internal.webapp.OSGiWebappClassLoader;
-import org.eclipse.jetty.osgi.boot.utils.EventSender;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.log.Log;
@@ -44,9 +38,7 @@
import org.eclipse.jetty.xml.XmlConfiguration;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
-import org.osgi.framework.ServiceRegistration;
import org.osgi.service.packageadmin.PackageAdmin;
@@ -55,7 +47,9 @@
/**
* AbstractWebAppProvider
*
- *
+ * Base class for Jetty DeploymentManager Providers that are capable of deploying a webapp,
+ * either from a bundle or an OSGi service.
+ *
*/
public abstract class AbstractWebAppProvider extends AbstractLifeCycle implements AppProvider
{
@@ -64,10 +58,9 @@
public static String __defaultConfigurations[] = {
"org.eclipse.jetty.osgi.boot.OSGiWebInfConfiguration",
"org.eclipse.jetty.webapp.WebXmlConfiguration",
- "org.eclipse.jetty.osgi.boot.OSGiMetaInfConfiguration",
+ "org.eclipse.jetty.webapp.MetaInfConfiguration",
"org.eclipse.jetty.webapp.FragmentConfiguration",
- "org.eclipse.jetty.webapp.JettyWebXmlConfiguration"//,
- //"org.eclipse.jetty.osgi.boot.jsp.TagLibOSGiConfiguration"
+ "org.eclipse.jetty.webapp.JettyWebXmlConfiguration"
};
public static void setDefaultConfigurations (String[] defaultConfigs)
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleContextProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleContextProvider.java
index 149aa99..92dcbd4 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleContextProvider.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleContextProvider.java
@@ -26,16 +26,11 @@
import java.util.Map;
import org.eclipse.jetty.deploy.App;
-import org.eclipse.jetty.deploy.DeploymentManager;
import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
-import org.eclipse.jetty.osgi.boot.utils.EventSender;
-import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.webapp.WebAppContext;
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
import org.osgi.framework.ServiceRegistration;
@@ -43,7 +38,7 @@
/**
* BundleContextProvider
*
- * Handles deploying bundles that define a context xml file for configuring them.
+ * Handles deploying OSGi bundles that define a context xml file for configuring them.
*
*
*/
@@ -136,6 +131,7 @@
}
apps.add(app);
getDeploymentManager().addApp(app);
+ added = true;
}
return added; //true if even 1 context from this bundle was added
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleProvider.java
index c87c071..e137269 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleProvider.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleProvider.java
@@ -20,6 +20,11 @@
import org.osgi.framework.Bundle;
+/**
+ * BundleProvider
+ *
+ * Jetty DeploymentManager Provider api for webapps or ContextHandlers that are discovered as osgi bundles.
+ */
public interface BundleProvider
{
public boolean bundleAdded (Bundle bundle) throws Exception;
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleWebAppProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleWebAppProvider.java
index 2a5e6e3..ab38f29 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleWebAppProvider.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/BundleWebAppProvider.java
@@ -25,7 +25,6 @@
import org.eclipse.jetty.deploy.App;
import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
-import org.eclipse.jetty.osgi.boot.utils.EventSender;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.osgi.framework.Bundle;
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/JettyBootstrapActivator.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/JettyBootstrapActivator.java
index 2ed6e7b..8763ece 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/JettyBootstrapActivator.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/JettyBootstrapActivator.java
@@ -18,45 +18,35 @@
package org.eclipse.jetty.osgi.boot;
-import java.util.Dictionary;
-import java.util.Hashtable;
-
import org.eclipse.jetty.osgi.boot.internal.serverfactory.DefaultJettyAtJettyHomeHelper;
import org.eclipse.jetty.osgi.boot.internal.serverfactory.JettyServerServiceTracker;
-import org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper;
-import org.eclipse.jetty.osgi.boot.internal.webapp.JettyContextHandlerServiceTracker;
-import org.eclipse.jetty.osgi.boot.internal.webapp.WebBundleTrackerCustomizer;
+import org.eclipse.jetty.osgi.boot.internal.webapp.BundleWatcher;
+import org.eclipse.jetty.osgi.boot.internal.webapp.ServiceWatcher;
import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandler;
-import org.eclipse.jetty.webapp.WebAppContext;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceRegistration;
import org.osgi.util.tracker.BundleTracker;
/**
+ * JettyBootstrapActivator
+ *
* Bootstrap jetty and publish a default Server instance as an OSGi service.
*
* Listen for other Server instances to be published as services and support them as deployment targets.
*
- * Listen for Bundles to be activated, and deploy those that represent webapps to one of the known Server instances.
+ * Listen for Bundles to be activated, and deploy those that represent webapps/ContextHandlers to one of the known Server instances.
*
- * <ol>
- * <li>basic servlet [ok]</li>
- * <li>basic jetty.xml [ok]</li>
- * <li>basic jetty.xml and jetty-plus.xml [ok]</li>
- * <li>basic jsp [ok]</li>
- * <li>jsp with tag-libs [ok]</li>
- * <li>test-jndi with atomikos and derby inside ${jetty.home}/lib/ext [ok]</li>
- * </ul>
*/
public class JettyBootstrapActivator implements BundleActivator
{
-
+ private static final Logger LOG = Log.getLogger(JettyBootstrapActivator.class);
+
private static JettyBootstrapActivator INSTANCE = null;
public static JettyBootstrapActivator getInstance()
@@ -66,7 +56,7 @@
private ServiceRegistration _registeredServer;
- private JettyContextHandlerServiceTracker _jettyContextHandlerTracker;
+ private ServiceWatcher _jettyContextHandlerTracker;
private PackageAdminServiceTracker _packageAdminServiceTracker;
@@ -75,7 +65,10 @@
private BundleContext _bundleContext;
private JettyServerServiceTracker _jettyServerServiceTracker;
-
+
+
+
+ /* ------------------------------------------------------------ */
/**
* Setup a new jetty Server, registers it as a service. Setup the Service
* tracker for the jetty ContextHandlers that are in charge of deploying the
@@ -84,7 +77,7 @@
*
* @param context
*/
- public void start(BundleContext context) throws Exception
+ public void start(final BundleContext context) throws Exception
{
INSTANCE = this;
_bundleContext = context;
@@ -98,18 +91,23 @@
context.addServiceListener(_jettyServerServiceTracker, "(objectclass=" + Server.class.getName() + ")");
// track ContextHandler class instances and deploy them to one of the known Servers
- _jettyContextHandlerTracker = new JettyContextHandlerServiceTracker();
+ _jettyContextHandlerTracker = new ServiceWatcher();
context.addServiceListener(_jettyContextHandlerTracker, "(objectclass=" + ContextHandler.class.getName() + ")");
// Create a default jetty instance right now.
- DefaultJettyAtJettyHomeHelper.startJettyAtJettyHome(context);
+ Server defaultServer = DefaultJettyAtJettyHomeHelper.startJettyAtJettyHome(context);
- // track Bundles and deploy those that represent webapps to one of the known Servers
- WebBundleTrackerCustomizer customizer = new WebBundleTrackerCustomizer();
- _webBundleTracker = new BundleTracker(context, Bundle.ACTIVE | Bundle.STOPPING, customizer);
- customizer.setAndOpenWebBundleTracker(_webBundleTracker);
+ //Create a bundle tracker to help deploy webapps and ContextHandlers
+ BundleWatcher bundleTrackerCustomizer = new BundleWatcher();
+ bundleTrackerCustomizer.setWaitForDefaultServer(defaultServer != null);
+ _webBundleTracker = new BundleTracker(context, Bundle.ACTIVE | Bundle.STOPPING, bundleTrackerCustomizer);
+ bundleTrackerCustomizer.setBundleTracker(_webBundleTracker);
+ bundleTrackerCustomizer.open();
}
-
+
+
+
+ /* ------------------------------------------------------------ */
/**
* Stop the activator.
*
@@ -120,7 +118,6 @@
{
try
{
-
if (_webBundleTracker != null)
{
_webBundleTracker.close();
@@ -164,122 +161,4 @@
INSTANCE = null;
}
}
-
- /**
- * Helper method that creates a new org.jetty.webapp.WebAppContext and
- * registers it as an OSGi service. The tracker
- * {@link JettyContextHandlerServiceTracker} will do the actual deployment.
- *
- * @param contributor The bundle
- * @param webappFolderPath The path to the root of the webapp. Must be a
- * path relative to bundle; either an absolute path.
- * @param contextPath The context path. Must start with "/"
- * @throws Exception
- */
- public static void registerWebapplication(Bundle contributor, String webappFolderPath, String contextPath) throws Exception
- {
- checkBundleActivated();
- WebAppContext contextHandler = new WebAppContext();
- Dictionary<String,String> dic = new Hashtable<String,String>();
- dic.put(OSGiWebappConstants.SERVICE_PROP_WAR, webappFolderPath);
- dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH, contextPath);
- String requireTldBundle = (String) contributor.getHeaders().get(OSGiWebappConstants.REQUIRE_TLD_BUNDLE);
- if (requireTldBundle != null)
- {
- dic.put(OSGiWebappConstants.SERVICE_PROP_REQUIRE_TLD_BUNDLE, requireTldBundle);
- }
- contributor.getBundleContext().registerService(ContextHandler.class.getName(), contextHandler, dic);
- }
-
- /**
- * Helper method that creates a new org.jetty.webapp.WebAppContext and
- * registers it as an OSGi service. The tracker
- * {@link JettyContextHandlerServiceTracker} will do the actual deployment.
- *
- * @param contributor The bundle
- * @param webappFolderPath The path to the root of the webapp. Must be a
- * path relative to bundle; either an absolute path.
- * @param contextPath The context path. Must start with "/"
- * @param dic TODO: parameter description
- * @throws Exception
- */
- public static void registerWebapplication(Bundle contributor, String webappFolderPath, String contextPath, Dictionary<String, String> dic) throws Exception
- {
- checkBundleActivated();
- WebAppContext contextHandler = new WebAppContext();
- dic.put(OSGiWebappConstants.SERVICE_PROP_WAR, webappFolderPath);
- dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH, contextPath);
- contributor.getBundleContext().registerService(ContextHandler.class.getName(), contextHandler, dic);
- }
-
- /**
- * Helper method that creates a new skeleton of a ContextHandler and
- * registers it as an OSGi service. The tracker
- * {@link JettyContextHandlerServiceTracker} will do the actual deployment.
- *
- * @param contributor The bundle that registers a new context
- * @param contextFilePath The path to the file inside the bundle that
- * defines the context.
- * @throws Exception
- */
- public static void registerContext(Bundle contributor, String contextFilePath) throws Exception
- {
- registerContext(contributor, contextFilePath, new Hashtable<String, String>());
- }
-
- /**
- * Helper method that creates a new skeleton of a ContextHandler and
- * registers it as an OSGi service. The tracker
- * {@link JettyContextHandlerServiceTracker} will do the actual deployment.
- *
- * @param contributor The bundle that registers a new context
- * @param contextFilePath The path to the file inside the bundle that
- * defines the context.
- * @param dic TODO: parameter description
- * @throws Exception
- */
- public static void registerContext(Bundle contributor, String contextFilePath, Dictionary<String, String> dic) throws Exception
- {
- checkBundleActivated();
- ContextHandler contextHandler = new ContextHandler();
- dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH, contextFilePath);
- dic.put(IWebBundleDeployerHelper.INTERNAL_SERVICE_PROP_UNKNOWN_CONTEXT_HANDLER_TYPE, Boolean.TRUE.toString());
- contributor.getBundleContext().registerService(ContextHandler.class.getName(), contextHandler, dic);
- }
-
- public static void unregister(String contextPath)
- {
- // todo
- }
-
- /**
- * Since org.eclipse.jetty.osgi.boot does not have a lazy activation policy
- * when one of the static methods to register a webapp is called we should
- * make sure that the bundle is started.
- */
- private static void checkBundleActivated()
- {
- if (INSTANCE == null)
- {
- Bundle thisBundle = FrameworkUtil.getBundle(JettyBootstrapActivator.class);
- try
- {
- thisBundle.start();
- }
- catch (BundleException e)
- {
- // nevermind.
- }
- }
- }
-
- /**
- * @return The bundle context for this bundle.
- */
- public static BundleContext getBundleContext()
- {
- checkBundleActivated();
- return INSTANCE._bundleContext;
- }
-
}
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiDeployer.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiDeployer.java
index 5f9321e..1b80e04 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiDeployer.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiDeployer.java
@@ -27,7 +27,9 @@
/**
* OSGiDeployer
*
- *
+ * Extension of standard Jetty deployer that emits OSGi EventAdmin
+ * events whenever a webapp is deployed into OSGi via Jetty.
+ *
*/
public class OSGiDeployer extends StandardDeployer
{
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiMetaInfConfiguration.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiMetaInfConfiguration.java
index bacc8ea..9767bd3 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiMetaInfConfiguration.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiMetaInfConfiguration.java
@@ -32,6 +32,14 @@
import org.eclipse.jetty.webapp.WebAppContext;
import org.osgi.framework.Bundle;
+/**
+ * OSGiMetaInfConfiguration
+ *
+ * Extension of standard Jetty MetaInfConfiguration class to handle OSGi bundle
+ * fragments that may also need to be scanned for META-INF info.
+ *
+ * @deprecated
+ */
public class OSGiMetaInfConfiguration extends MetaInfConfiguration
{
private static final Logger LOG = Log.getLogger(OSGiMetaInfConfiguration.class);
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiServerConstants.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiServerConstants.java
index 2f9df55..67ef323 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiServerConstants.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiServerConstants.java
@@ -19,6 +19,8 @@
package org.eclipse.jetty.osgi.boot;
/**
+ * OSGiServerConstants
+ *
* Name of the properties that configure a jetty Server OSGi service.
*/
public class OSGiServerConstants
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiUndeployer.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiUndeployer.java
index ac06874..674f960 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiUndeployer.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiUndeployer.java
@@ -29,7 +29,9 @@
/**
* OSGiUndeployer
*
- *
+ * Extension of the Jetty Undeployer which emits OSGi EventAdmin events
+ * whenever a webapp is undeployed from Jetty.
+ *
*/
public class OSGiUndeployer extends StandardUndeployer
{
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebInfConfiguration.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebInfConfiguration.java
index 988ebb2..76eb8ad 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebInfConfiguration.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebInfConfiguration.java
@@ -52,7 +52,7 @@
public static final String CONTAINER_BUNDLE_PATTERN = "org.eclipse.jetty.server.webapp.containerIncludeBundlePattern";
-
+ /* ------------------------------------------------------------ */
/**
* Check to see if there have been any bundle symbolic names added of bundles that should be
* regarded as being on the container classpath, and scanned for fragments, tlds etc etc.
@@ -120,7 +120,7 @@
}
-
+ /* ------------------------------------------------------------ */
/**
* Consider the fragment bundles associated with the bundle of the webapp being deployed.
*
@@ -148,7 +148,7 @@
return mergedResources;
}
-
+ /* ------------------------------------------------------------ */
/**
* Allow fragments to supply some resources that are added to the baseResource of the webapp.
*
@@ -227,11 +227,10 @@
resources[resources.length-1] = context.getBaseResource();
context.setBaseResource(new ResourceCollection(resources));
}
-
}
-
+ /* ------------------------------------------------------------ */
/**
* Resolves the bundle. Usually that would be a single URL per bundle. But we do some more work if there are jars
* embedded in the bundle.
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebappConstants.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebappConstants.java
index 1908eb2..e97457a 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebappConstants.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiWebappConstants.java
@@ -19,7 +19,12 @@
package org.eclipse.jetty.osgi.boot;
/**
- * Name of the service properties for a ContextHandler that configure a webapp deployed on jetty OSGi.
+ * OSGiWebappConstants
+ *
+ *
+ * Constants (MANIFEST headers, service properties etc) associated with deploying
+ * webapps into OSGi via Jetty.
+ *
*/
public class OSGiWebappConstants
{
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceContextProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceContextProvider.java
index 2e36904..a228a62 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceContextProvider.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceContextProvider.java
@@ -38,7 +38,9 @@
/**
* ServiceContextProvider
*
- *
+ * Jetty DeploymentManager Provider that is able to deploy ContextHandlers discovered via OSGi as services.
+ *
+ *
*/
public class ServiceContextProvider extends AbstractContextProvider implements ServiceProvider
{
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceProvider.java
index f2304c6..34335cf 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceProvider.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceProvider.java
@@ -21,6 +21,11 @@
import org.eclipse.jetty.server.handler.ContextHandler;
import org.osgi.framework.ServiceReference;
+/**
+ * ServiceProvider
+ *
+ * Jetty DeploymentManager Provider api for webapps or ContextHandlers that are discovered as OSGi services.
+ */
public interface ServiceProvider
{
public boolean serviceAdded (ServiceReference ref, ContextHandler handler) throws Exception;
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceWebAppProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceWebAppProvider.java
index e3f97f0..6008aa0 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceWebAppProvider.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/ServiceWebAppProvider.java
@@ -27,7 +27,6 @@
import org.eclipse.jetty.deploy.AppProvider;
import org.eclipse.jetty.deploy.DeploymentManager;
import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
-import org.eclipse.jetty.osgi.boot.utils.EventSender;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/jsp/TldLocatableURLClassloader.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/jsp/TldLocatableURLClassloader.java
deleted file mode 100644
index 4b48aef..0000000
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/jsp/TldLocatableURLClassloader.java
+++ /dev/null
@@ -1,65 +0,0 @@
-//
-// ========================================================================
-// Copyright (c) 1995-2013 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.osgi.boot.internal.jsp;
-
-import java.net.URL;
-import java.net.URLClassLoader;
-
-/**
- * Tricky url classloader. In fact we don't want a real URLClassLoader: we want
- * OSGi to provide its classloader and let it does. But to let
- * {@link org.apache.jasper.compiler.TldLocationsCache} find the core tlds
- * inside the jars we must be a URLClassLoader that returns an array of jars
- * where tlds are stored when the method getURLs is called.
- */
-public class TldLocatableURLClassloader extends URLClassLoader
-{
-
- private URL[] _jarsWithTldsInside;
-
- public TldLocatableURLClassloader(ClassLoader osgiClassLoader, URL[] jarsWithTldsInside)
- {
- super(new URL[] {},osgiClassLoader);
- _jarsWithTldsInside = jarsWithTldsInside;
- }
-
- /**
- * @return the jars that contains tlds so that TldLocationsCache or
- * TldScanner can find them.
- */
- @Override
- public URL[] getURLs()
- {
- return _jarsWithTldsInside;
- }
-
- public String toString()
- {
- StringBuilder builder = new StringBuilder();
-
- if (_jarsWithTldsInside != null)
- {
- for (URL u:_jarsWithTldsInside)
- builder.append(" "+u.toString());
- return builder.toString();
- }
- else
- return super.toString();
- }
-}
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/jsp/TldLocatableURLClassloaderWithInsertedJettyClassloader.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/jsp/TldLocatableURLClassloaderWithInsertedJettyClassloader.java
deleted file mode 100644
index e4cf805..0000000
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/jsp/TldLocatableURLClassloaderWithInsertedJettyClassloader.java
+++ /dev/null
@@ -1,69 +0,0 @@
-//
-// ========================================================================
-// Copyright (c) 1995-2013 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.osgi.boot.internal.jsp;
-
-import java.net.URL;
-
-/**
- * Add a classloader to the
- * org.apache.jasper.compiler.TldLocatableURLClassloader. Hopefuly not
- * necessary: still experimenting.
- *
- * @see TldLocatableURLClassloader
- */
-public class TldLocatableURLClassloaderWithInsertedJettyClassloader extends TldLocatableURLClassloader
-{
-
- private ClassLoader _internalClassLoader;
-
- /**
- *
- * @param osgiClassLoaderParent
- * The parent classloader
- * @param internalClassLoader
- * The classloader that will be at the same level than the
- * jarsWithTldsInside
- * @param jarsWithTldsInside
- * jars that are scanned for tld files.
- */
- public TldLocatableURLClassloaderWithInsertedJettyClassloader(ClassLoader osgiClassLoaderParent, ClassLoader internalClassLoader, URL[] jarsWithTldsInside)
- {
- super(osgiClassLoaderParent,jarsWithTldsInside);
- _internalClassLoader = internalClassLoader;
- }
-
- protected Class<?> findClass(String name) throws ClassNotFoundException
- {
- try
- {
- return super.findClass(name);
- }
- catch (ClassNotFoundException cne)
- {
- if (_internalClassLoader != null)
- {
- return _internalClassLoader.loadClass(name);
- }
- else
- {
- throw cne;
- }
- }
- }
-}
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java
index bef4dcf..a89ff5b 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/DefaultJettyAtJettyHomeHelper.java
@@ -29,7 +29,6 @@
import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator;
import org.eclipse.jetty.osgi.boot.OSGiServerConstants;
import org.eclipse.jetty.osgi.boot.internal.webapp.BundleFileLocatorHelperFactory;
-import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@@ -40,9 +39,12 @@
* DefaultJettyAtJettyHomeHelper
*
*
+ * Creates a default instance of Jetty, based on the values of the
+ * System properties "jetty.home" or "jetty.home.bundle", one of which
+ * must be specified in order to create the default instance.
+ *
* Called by the {@link JettyBootstrapActivator} during the starting of the
- * bundle. If the system property 'jetty.home' is defined and points to a
- * folder, then setup the corresponding jetty server.
+ * bundle.
*/
public class DefaultJettyAtJettyHomeHelper
{
@@ -64,6 +66,7 @@
public static final String DEFAULT_JETTYHOME = "/jettyhome/";
+
/* ------------------------------------------------------------ */
/**
* Called by the JettyBootStrapActivator. If the system property jetty.home
@@ -87,7 +90,7 @@
* as part of their properties.
* </p>
*/
- public static void startJettyAtJettyHome(BundleContext bundleContext) throws Exception
+ public static Server startJettyAtJettyHome(BundleContext bundleContext) throws Exception
{
String jettyHomeSysProp = System.getProperty(OSGiServerConstants.JETTY_HOME);
String jettyHomeBundleSysProp = System.getProperty(OSGiServerConstants.JETTY_HOME_BUNDLE);
@@ -109,7 +112,7 @@
if (!jettyHome.exists() || !jettyHome.isDirectory())
{
LOG.warn("Unable to locate the jetty.home folder " + jettyHomeSysProp);
- return;
+ return null;
}
}
else if (jettyHomeBundleSysProp != null)
@@ -126,14 +129,14 @@
if (jettyHomeBundle == null)
{
LOG.warn("Unable to find the jetty.home.bundle named " + jettyHomeSysProp);
- return;
+ return null;
}
}
if (jettyHome == null && jettyHomeBundle == null)
{
LOG.warn("No default jetty created.");
- return;
+ return null;
}
Server server = new Server();
@@ -152,8 +155,11 @@
setProperty(properties, OSGiServerConstants.JETTY_PORT, System.getProperty(OSGiServerConstants.JETTY_PORT));
setProperty(properties, OSGiServerConstants.JETTY_PORT_SSL, System.getProperty(OSGiServerConstants.JETTY_PORT_SSL));
- //register the Server instance as an OSGi service.
+ //Register the default Server instance as an OSGi service.
+ //The JettyServerServiceTracker will notice it and configure it.
bundleContext.registerService(Server.class.getName(), server, properties);
+
+ return server;
}
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/JettyServerServiceTracker.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/JettyServerServiceTracker.java
index e172c75..b946cd8 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/JettyServerServiceTracker.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/JettyServerServiceTracker.java
@@ -32,8 +32,11 @@
import org.osgi.framework.ServiceReference;
/**
- * Deploy the jetty server instances when they are registered as an OSGi
- * service.
+ * JettyServerServiceTracker
+ *
+ * Tracks instances of Jetty Servers, and configures them so that they can deploy
+ * webapps or ContextHandlers discovered from the OSGi environment.
+ *
*/
public class JettyServerServiceTracker implements ServiceListener, IManagedJettyServerRegistry
{
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/ServerInstanceWrapper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/ServerInstanceWrapper.java
index a7e9daa..209fee6 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/ServerInstanceWrapper.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/serverfactory/ServerInstanceWrapper.java
@@ -19,7 +19,6 @@
package org.eclipse.jetty.osgi.boot.internal.serverfactory;
import java.io.File;
-import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
@@ -27,8 +26,10 @@
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.StringTokenizer;
import org.eclipse.jetty.deploy.AppLifeCycle;
@@ -44,11 +45,10 @@
import org.eclipse.jetty.osgi.boot.OSGiUndeployer;
import org.eclipse.jetty.osgi.boot.ServiceContextProvider;
import org.eclipse.jetty.osgi.boot.ServiceWebAppProvider;
-import org.eclipse.jetty.osgi.boot.internal.jsp.TldLocatableURLClassloader;
import org.eclipse.jetty.osgi.boot.internal.webapp.BundleFileLocatorHelperFactory;
import org.eclipse.jetty.osgi.boot.internal.webapp.LibExtClassLoaderHelper;
-import org.eclipse.jetty.osgi.boot.internal.webapp.WebBundleTrackerCustomizer;
-import org.eclipse.jetty.osgi.boot.utils.WebappRegistrationCustomizer;
+import org.eclipse.jetty.osgi.boot.utils.FakeURLClassLoader;
+import org.eclipse.jetty.osgi.boot.utils.TldBundleDiscoverer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.util.IO;
@@ -72,6 +72,9 @@
* support the case where the bundle is zipped.
*/
public static final String PROPERTY_THIS_JETTY_XML_FOLDER_URL = "this.jetty.xml.parent.folder.url";
+
+
+ private static Collection<TldBundleDiscoverer> __containerTldBundleDiscoverers = new ArrayList<TldBundleDiscoverer>();
private static Logger LOG = Log.getLogger(ServerInstanceWrapper.class.getName());
@@ -96,6 +99,21 @@
private DeploymentManager _deploymentManager;
+
+ /* ------------------------------------------------------------ */
+ public static void addContainerTldBundleDiscoverer (TldBundleDiscoverer tldBundleDiscoverer)
+ {
+ __containerTldBundleDiscoverers.add(tldBundleDiscoverer);
+ }
+
+ /* ------------------------------------------------------------ */
+ public static Collection<TldBundleDiscoverer> getContainerTldBundleDiscoverers()
+ {
+ return __containerTldBundleDiscoverers;
+ }
+
+
+
/* ------------------------------------------------------------ */
public ServerInstanceWrapper(String managedServerName)
{
@@ -173,9 +191,29 @@
configure(server, props);
init();
+
+ //if support for jsp is enabled, we need to convert locations of bundles that contain tlds into urls.
+ //these are tlds that we want jasper to treat as if they are on the container's classpath. Web bundles
+ //can use the Require-TldBundle MANIFEST header to name other tld-containing bundles that should be regarded
+ //as on the webapp classpath.
+ if (!__containerTldBundleDiscoverers.isEmpty())
+ {
+ Set<URL> urls = new HashSet<URL>();
+ //discover bundles with tlds that need to be on the container's classpath as URLs
+ for (TldBundleDiscoverer d:__containerTldBundleDiscoverers)
+ {
+ URL[] list = d.getUrlsForBundlesWithTlds(_deploymentManager, BundleFileLocatorHelperFactory.getFactory().getHelper());
+ if (list != null)
+ {
+ for (URL u:list)
+ urls.add(u);
+ }
+ }
+ _commonParentClassLoaderForWebapps = new FakeURLClassLoader(libExtClassLoader, urls.toArray(new URL[urls.size()]));
+ }
+ else
+ _commonParentClassLoaderForWebapps = libExtClassLoader;
- URL[] jarsWithTlds = getJarsWithTlds();
- _commonParentClassLoaderForWebapps = jarsWithTlds == null ? libExtClassLoader : new TldLocatableURLClassloader(libExtClassLoader, jarsWithTlds);
if (LOG.isDebugEnabled()) LOG.debug("common classloader = "+_commonParentClassLoaderForWebapps);
@@ -219,54 +257,7 @@
}
- /* ------------------------------------------------------------ */
- /**
- * TODO: right now only the jetty-jsp bundle is scanned for common taglibs.
- * Should support a way to plug more bundles that contain taglibs.
- *
- * The jasper TldScanner expects a URLClassloader to parse a jar for the
- * /META-INF/*.tld it may contain. We place the bundles that we know contain
- * such tag-libraries. Please note that it will work if and only if the
- * bundle is a jar (!) Currently we just hardcode the bundle that contains
- * the jstl implementation.
- *
- * A workaround when the tld cannot be parsed with this method is to copy
- * and paste it inside the WEB-INF of the webapplication where it is used.
- *
- * Support only 2 types of packaging for the bundle: - the bundle is a jar
- * (recommended for runtime.) - the bundle is a folder and contain jars in
- * the root and/or in the lib folder (nice for PDE development situations)
- * Unsupported: the bundle is a jar that embeds more jars.
- *
- * @return
- * @throws Exception
- */
- private URL[] getJarsWithTlds() throws Exception
- {
-
- //Jars that are added onto the equivalent of the container classpath are:
- // jstl jars: identified by the class WhenTag (and the boot-bundle manifest imports the jstl packages
- // bundles identified by System property org.eclipse.jetty.osgi.tldbundles
- // bundle symbolic name patterns defined in the DeploymentManager
- //
- // Any bundles mentioned in the Require-TldBundle manifest header of the webapp bundle MUST ALSO HAVE Import-Bundle
- // in order to get them onto the classpath of the webapp.
-
- ArrayList<URL> res = new ArrayList<URL>();
- for (WebappRegistrationCustomizer regCustomizer : WebBundleTrackerCustomizer.JSP_REGISTRATION_HELPERS)
- {
- URL[] urls = regCustomizer.getJarsWithTlds(_deploymentManager, BundleFileLocatorHelperFactory.getFactory().getHelper());
- for (URL url : urls)
- {
- if (!res.contains(url)) res.add(url);
- }
- }
- if (!res.isEmpty())
- return res.toArray(new URL[res.size()]);
- else
- return null;
- }
-
+
/* ------------------------------------------------------------ */
private void configure(Server server, Dictionary props) throws Exception
@@ -340,7 +331,9 @@
}
}
-
+
+
+ /* ------------------------------------------------------------ */
/**
* Must be called after the server is configured.
*
@@ -438,7 +431,9 @@
}
}
}
-
+
+
+ /* ------------------------------------------------------------ */
/**
* @return The default folder in which the context files of the osgi bundles
* are located and watched. Or null when the system property
@@ -463,7 +458,7 @@
return new File(jettyHome, "/contexts");
}
-
+ /* ------------------------------------------------------------ */
/**
* @return the urls in this string.
*/
@@ -485,7 +480,9 @@
}
return urls;
}
-
+
+
+ /* ------------------------------------------------------------ */
/**
* Get the folders that might contain jars for the legacy J2EE shared
* libraries
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/BundleWatcher.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/BundleWatcher.java
new file mode 100644
index 0000000..74622c3
--- /dev/null
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/BundleWatcher.java
@@ -0,0 +1,317 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2013 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.osgi.boot.internal.webapp;
+
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.jetty.osgi.boot.BundleProvider;
+import org.eclipse.jetty.osgi.boot.OSGiServerConstants;
+import org.eclipse.jetty.osgi.boot.utils.TldBundleDiscoverer;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.osgi.util.tracker.BundleTracker;
+import org.osgi.util.tracker.BundleTrackerCustomizer;
+import org.osgi.util.tracker.ServiceTracker;
+
+/**
+ * BundleWatcher
+ *
+ *
+ * Tracks the installation and removal of Bundles in the OSGi environment. Any bundles
+ * that are added are passed to the set of Jetty DeploymentManager providers to see if
+ * the bundle should be deployed as a webapp or ContextHandler into Jetty.
+ *
+ * @author hmalphettes
+ */
+public class BundleWatcher implements BundleTrackerCustomizer
+{
+ private static final Logger LOG = Log.getLogger(BundleWatcher.class);
+
+ public static Collection<TldBundleDiscoverer> JSP_REGISTRATION_HELPERS = new ArrayList<TldBundleDiscoverer>();
+
+
+ public static final String FILTER = "(objectclass=" + BundleProvider.class.getName() + ")";
+ private ServiceTracker _serviceTracker;
+ private BundleTracker _bundleTracker;
+ private boolean _waitForDefaultServer = true;
+ private boolean _defaultServerReady = false;
+ private Bundle _bundle = null;
+
+
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @throws Exception
+ */
+ public BundleWatcher() throws Exception
+ {
+ _bundle = FrameworkUtil.getBundle(this.getClass());
+ //Track all BundleProviders (Jetty DeploymentManager Providers that can deploy bundles)
+ _serviceTracker = new ServiceTracker(_bundle.getBundleContext(), FrameworkUtil.createFilter(FILTER),null);
+ _serviceTracker.open();
+ }
+
+
+ /* ------------------------------------------------------------ */
+ public boolean isWaitForDefaultServer()
+ {
+ return _waitForDefaultServer;
+ }
+
+
+ /* ------------------------------------------------------------ */
+ public void setWaitForDefaultServer(boolean waitForDefaultServer)
+ {
+ _waitForDefaultServer = waitForDefaultServer;
+ }
+
+
+ /* ------------------------------------------------------------ */
+ public void setBundleTracker (BundleTracker bundleTracker)
+ {
+ _bundleTracker = bundleTracker;
+ }
+
+
+ /* ------------------------------------------------------------ */
+ public void open () throws Exception
+ {
+ if (_waitForDefaultServer && !_defaultServerReady)
+ {
+ String filter = "(&(objectclass=" + BundleProvider.class.getName() + ")"+
+ "("+OSGiServerConstants.MANAGED_JETTY_SERVER_NAME+"="+OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME+"))";
+
+ ServiceTracker defaultServerTracker = new ServiceTracker(_bundle.getBundleContext(),
+ FrameworkUtil.createFilter(filter),null)
+ {
+ public Object addingService(ServiceReference reference)
+ {
+ try
+ {
+ Object object = super.addingService(reference);
+ LOG.debug("Default Jetty Server registered {}", reference);
+ _defaultServerReady = true;
+ openBundleTracker();
+ return object;
+ }
+ catch (Exception e)
+ {
+ throw new IllegalStateException(e);
+ }
+ }
+ };
+ defaultServerTracker.open();
+ }
+ else
+ openBundleTracker();
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param managedServerName
+ * @return
+ */
+ public Map<ServiceReference, BundleProvider> getDeployers(String managedServerName)
+ {
+ if (managedServerName == null)
+ managedServerName = OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME;
+
+ Map<ServiceReference, BundleProvider> candidates = new HashMap<ServiceReference, BundleProvider>();
+
+ ServiceReference[] references = _serviceTracker.getServiceReferences();
+ if (references != null)
+ {
+ for (ServiceReference ref:references)
+ {
+ String name = (String)ref.getProperty(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
+ if (managedServerName.equalsIgnoreCase(name))
+ {
+ BundleProvider candidate = (BundleProvider)_serviceTracker.getService(ref);
+ if (candidate != null)
+ candidates.put(ref, candidate);
+ }
+ }
+ }
+ return candidates;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * A bundle is being added to the <code>BundleTracker</code>.
+ *
+ * <p>
+ * This method is called before a bundle which matched the search parameters
+ * of the <code>BundleTracker</code> is added to the
+ * <code>BundleTracker</code>. This method should return the object to be
+ * tracked for the specified <code>Bundle</code>. The returned object is
+ * stored in the <code>BundleTracker</code> and is available from the
+ * {@link BundleTracker#getObject(Bundle) getObject} method.
+ *
+ * @param bundle The <code>Bundle</code> being added to the
+ * <code>BundleTracker</code>.
+ * @param event The bundle event which caused this customizer method to be
+ * called or <code>null</code> if there is no bundle event
+ * associated with the call to this method.
+ * @return The object to be tracked for the specified <code>Bundle</code>
+ * object or <code>null</code> if the specified <code>Bundle</code>
+ * object should not be tracked.
+ */
+ public Object addingBundle(Bundle bundle, BundleEvent event)
+ {
+ if (bundle.getState() == Bundle.ACTIVE)
+ {
+ register(bundle);
+ }
+ else if (bundle.getState() == Bundle.STOPPING)
+ {
+ unregister(bundle);
+ }
+ else
+ {
+ // we should not be called in that state as
+ // we are registered only for ACTIVE and STOPPING
+ }
+ return null;
+ }
+
+
+ /* ------------------------------------------------------------ */
+ /**
+ * A bundle tracked by the <code>BundleTracker</code> has been modified.
+ *
+ * <p>
+ * This method is called when a bundle being tracked by the
+ * <code>BundleTracker</code> has had its state modified.
+ *
+ * @param bundle The <code>Bundle</code> whose state has been modified.
+ * @param event The bundle event which caused this customizer method to be
+ * called or <code>null</code> if there is no bundle event
+ * associated with the call to this method.
+ * @param object The tracked object for the specified bundle.
+ */
+ public void modifiedBundle(Bundle bundle, BundleEvent event, Object object)
+ {
+ if (bundle.getState() == Bundle.STOPPING || bundle.getState() == Bundle.ACTIVE)
+ {
+ unregister(bundle);
+ }
+ if (bundle.getState() == Bundle.ACTIVE)
+ {
+ register(bundle);
+ }
+ }
+
+
+ /* ------------------------------------------------------------ */
+ /**
+ * A bundle tracked by the <code>BundleTracker</code> has been removed.
+ *
+ * <p>
+ * This method is called after a bundle is no longer being tracked by the
+ * <code>BundleTracker</code>.
+ *
+ * @param bundle The <code>Bundle</code> that has been removed.
+ * @param event The bundle event which caused this customizer method to be
+ * called or <code>null</code> if there is no bundle event
+ * associated with the call to this method.
+ * @param object The tracked object for the specified bundle.
+ */
+ public void removedBundle(Bundle bundle, BundleEvent event, Object object)
+ {
+ unregister(bundle);
+ }
+
+
+ protected void openBundleTracker()
+ {
+ _bundleTracker.open();
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param bundle
+ * @return true if this bundle can be deployed into Jetty
+ */
+ private boolean register(Bundle bundle)
+ {
+ if (bundle == null)
+ return false;
+
+ //It might be a bundle that is deployable by Jetty.
+ //Use any named Server instance provided, defaulting to the default Server instance if none supplied
+ boolean deployed = false;
+ String serverName = (String)bundle.getHeaders().get(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
+ Map<ServiceReference, BundleProvider> candidates = getDeployers(serverName);
+ if (candidates != null)
+ {
+ Iterator<Entry<ServiceReference, BundleProvider>> itor = candidates.entrySet().iterator();
+ while (!deployed && itor.hasNext())
+ {
+ Entry<ServiceReference, BundleProvider> e = itor.next();
+ try
+ {
+ deployed = e.getValue().bundleAdded(bundle);
+ }
+ catch (Exception x)
+ {
+ LOG.warn("Error deploying bundle for jetty context", x);
+ }
+ }
+ }
+
+ return deployed;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param bundle
+ */
+ private void unregister(Bundle bundle)
+ {
+ boolean undeployed = false;
+ String serverName = (String)bundle.getHeaders().get(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME);
+ Map<ServiceReference, BundleProvider> candidates = getDeployers(serverName);
+ if (candidates != null)
+ {
+ Iterator<Entry<ServiceReference, BundleProvider>> itor = candidates.entrySet().iterator();
+ while (!undeployed && itor.hasNext())
+ {
+ Entry<ServiceReference, BundleProvider> e = itor.next();
+ try
+ {
+ undeployed = e.getValue().bundleRemoved(bundle);
+ }
+ catch (Exception x)
+ {
+ LOG.warn("Error undeploying Bundle representing jetty deployable ", x);
+ }
+ }
+ }
+ }
+}
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/IWebBundleDeployerHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/IWebBundleDeployerHelper.java
deleted file mode 100644
index 1c5cd3e..0000000
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/IWebBundleDeployerHelper.java
+++ /dev/null
@@ -1,88 +0,0 @@
-//
-// ========================================================================
-// Copyright (c) 1995-2013 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.osgi.boot.internal.webapp;
-
-
-import org.eclipse.jetty.server.handler.ContextHandler;
-import org.eclipse.jetty.webapp.WebAppContext;
-import org.osgi.framework.Bundle;
-
-/**
- * Internal interface for the class that deploys a webapp on a server. Used as
- * we migrate from the single instance of the jety server to multiple jetty
- * servers.
- */
-public interface IWebBundleDeployerHelper
-{
-
- /**
- * when this property is present, the type of context handler registered is
- * not known in advance.
- */
- public static final String INTERNAL_SERVICE_PROP_UNKNOWN_CONTEXT_HANDLER_TYPE = "unknownContextHandlerType";
-
- /**
- * Deploy a new web application on the jetty server.
- *
- * @param bundle The bundle
- * @param webappFolderPath The path to the root of the webapp. Must be a
- * path relative to bundle; either an absolute path.
- * @param contextPath The context path. Must start with "/"
- * @param extraClasspath
- * @param overrideBundleInstallLocation
- * @param requireTldBundle The list of bundles's symbolic names that contain
- * tld files that are required by this WAB.
- * @param webXmlPath
- * @param defaultWebXmlPath TODO: parameter description
- * @return The contexthandler created and started
- * @throws Exception
- */
- public abstract WebAppContext registerWebapplication(Bundle bundle, String webappFolderPath, String contextPath, String extraClasspath,
- String overrideBundleInstallLocation, String requireTldBundle, String webXmlPath,
- String defaultWebXmlPath, WebAppContext webAppContext) throws Exception;
-
- /**
- * Stop a ContextHandler and remove it from the collection.
- *
- * @see ContextDeployer#undeploy
- * @param contextHandler
- * @throws Exception
- */
- public abstract void unregister(ContextHandler contextHandler) throws Exception;
-
- /**
- * This type of registration relies on jetty's complete context xml file.
- * Context encompasses jndi and all other things. This makes the definition
- * of the webapp a lot more self-contained.
- *
- * @param contributor
- * @param contextFileRelativePath
- * @param extraClasspath
- * @param overrideBundleInstallLocation
- * @param requireTldBundle The list of bundles'symbolic name that contain
- * tld files for this webapp.
- * @param handler the context handler passed in the server reference that
- * will be configured, deployed and started.
- * @return The contexthandler created and started
- * @throws Exception
- */
- public abstract ContextHandler registerContext(Bundle contributor, String contextFileRelativePath, String extraClasspath,
- String overrideBundleInstallLocation, String requireTldBundle, ContextHandler handler) throws Exception;
-
-}
\ No newline at end of file
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/LibExtClassLoaderHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/LibExtClassLoaderHelper.java
index c66fa26..7673834 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/LibExtClassLoaderHelper.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/LibExtClassLoaderHelper.java
@@ -33,6 +33,9 @@
import org.eclipse.jetty.server.Server;
/**
+ * LibExtClassLoaderHelper
+ *
+ *
* Helper to create a URL class-loader with the jars inside
* ${jetty.home}/lib/ext and ${jetty.home}/resources. In an ideal world, every
* library is an OSGi bundle that does loads nicely. To support standard jars or
@@ -40,57 +43,40 @@
* inserting the jars in the usual jetty/lib/ext folders in the proper classpath
* for the webapps.
* <p>
- * Also the folder resources typically contains central configuration files for
- * things like: log config and others. We enable fragments to register classes
- * that are called back and passed those resources to do what they need to do.
+ * The drawback is that those jars will not be available in the OSGi
+ * classloader.
* </p>
* <p>
- * For example the test-jndi webapplication depends on derby, derbytools,
- * atomikos none of them are osgi bundles. we can either re-package them or we
- * can place them in the usual lib/ext. <br/>
- * In fact jasper's jsp libraries should maybe place in lib/ext too.
- * </p>
- * <p>
- * The drawback is that those libraries will not be available in the OSGi
- * classloader. Note that we could have setup those jars as embedded jars of the
- * current bundle. However, we would need to know in advance what are those jars
- * which was not acceptable. Also having those jars in a URLClassLoader seem to
- * be required for some cases. For example jaspers' TldLocationsCache (replaced
- * by TldScanner for servlet-3.0). <br/>
- * Also all the dependencies of those libraries must be resolvable directly from
- * the JettyBootstrapActivator bundle as it is set as the parent classloader. For
- * example: if atomikos is placed in lib/ext it will work if and only if
- * JettyBootstrapActivator import the necessary packages from javax.naming*,
- * javax.transaction*, javax.mail* etc Most of the common cases of javax are
- * added as optional import packages into jetty bootstrapper plugin. When there
- * are not covered: please make a request or create a fragment or register a
- * bundle with a buddy-policy onto the jetty bootstrapper..
- * </p>
- * <p>
- * Alternatives to placing jars in lib/ext
+ * Alternatives to placing jars in lib/ext:
* <ol>
- * <li>Bundle the jars in an osgi bundle. Have the webapp(s) that context
- * depends on them depend on that bundle. Things will go well for jetty.</li>
+ * <li>Bundle the jars in an osgi bundle. Have the webapp(s) that need these jars
+ * depend on that bundle.</li>
* <li>Bundle those jars in an osgi bundle-fragment that targets the
* jetty-bootstrap bundle</li>
* <li>Use equinox Buddy-Policy: register a buddy of the jetty bootstrapper
- * bundle. (least favorite: it will work only on equinox)</li>
+ * bundle. (Note: it will work only on equinox)</li>
* </ol>
* </p>
*/
public class LibExtClassLoaderHelper
{
-
+ /* ------------------------------------------------------------ */
/**
- * Class called back
+ * IFilesInJettyHomeResourcesProcessor
+ *
+ * Interface for callback impls
*/
public interface IFilesInJettyHomeResourcesProcessor
{
void processFilesInResourcesFolder(File jettyHome, Map<String, File> filesInResourcesFolder);
}
+
+
public static Set<IFilesInJettyHomeResourcesProcessor> registeredFilesInJettyHomeResourcesProcessors = new HashSet<IFilesInJettyHomeResourcesProcessor>();
+
+ /* ------------------------------------------------------------ */
/**
* @param server
* @return a url classloader with the jars of resources, lib/ext and the
@@ -145,6 +131,8 @@
return new URLClassLoader(urls.toArray(new URL[urls.size()]), parentClassLoader);
}
+
+ /* ------------------------------------------------------------ */
/**
* @param server
* @return a url classloader with the jars of resources, lib/ext and the
@@ -188,6 +176,7 @@
return new URLClassLoader(urls.toArray(new URL[urls.size()]), parentClassLoader);
}
+ /* ------------------------------------------------------------ */
/**
* When we find files typically used for central logging configuration we do
* what it takes in this method to do what the user expects. Without
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java
index 5f7e644..e963b91 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/OSGiWebappClassLoader.java
@@ -33,7 +33,6 @@
import javax.servlet.http.HttpServlet;
-import org.eclipse.jetty.osgi.boot.utils.BundleClassLoaderHelper;
import org.eclipse.jetty.osgi.boot.utils.BundleClassLoaderHelperFactory;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@@ -44,8 +43,10 @@
import org.osgi.framework.BundleReference;
/**
- * Extends the webappclassloader to insert the classloader provided by the osgi
- * bundle at the same level than any other jars palced in the webappclassloader.
+ * OSGiWebappClassLoader
+ *
+ *
+ * Extends the webapp classloader to also use the classloader of the Bundle defining the webapp.
*/
public class OSGiWebappClassLoader extends WebAppClassLoader implements BundleReference
{
@@ -79,10 +80,9 @@
private boolean _lookInOsgiFirst = true;
- private Set<String> _libsAlreadyInManifest = new HashSet<String>();
-
+ /* ------------------------------------------------------------ */
/**
- * @param parent The parent classloader. In this case
+ * @param parent The parent classloader.
* @param context The WebAppContext
* @param contributor The bundle that defines this web-application.
* @throws IOException
@@ -94,7 +94,10 @@
_contributor = contributor;
_osgiBundleClassLoader = BundleClassLoaderHelperFactory.getFactory().getHelper().getBundleClassLoader(contributor);
}
-
+
+
+
+ /* ------------------------------------------------------------ */
/**
* Returns the <code>Bundle</code> that defined this web-application.
*
@@ -106,17 +109,7 @@
return _contributor;
}
- /**
- * Reads the manifest. If the manifest is already configured to loads a few
- * libs we should not add them to the classpath of the webapp. Not really
- * important as we resolve classes through the osgi classloader first and
- * then default on the libs of the webapp.
- */
- private void computeLibsAlreadyInOSGiClassLoader()
- {
- // TODO
- }
-
+ /* ------------------------------------------------------------ */
@Override
public Enumeration<URL> getResources(String name) throws IOException
{
@@ -131,7 +124,10 @@
return Collections.enumeration(toList(urls, osgiUrls));
}
}
-
+
+
+
+ /* ------------------------------------------------------------ */
@Override
public URL getResource(String name)
{
@@ -146,7 +142,10 @@
return url != null ? url : _osgiBundleClassLoader.getResource(name);
}
}
-
+
+
+
+ /* ------------------------------------------------------------ */
private List<URL> toList(Enumeration<URL> e, Enumeration<URL> e2)
{
List<URL> list = new ArrayList<URL>();
@@ -157,9 +156,8 @@
return list;
}
- /**
- *
- */
+
+ /* ------------------------------------------------------------ */
protected Class<?> findClass(String name) throws ClassNotFoundException
{
try
@@ -178,7 +176,10 @@
}
}
}
-
+
+
+
+ /* ------------------------------------------------------------ */
/**
* Parse the classpath ourselves to be able to filter things. This is a
* derivative work of the super class
@@ -207,6 +208,8 @@
}
+
+ /* ------------------------------------------------------------ */
/**
* @param lib
* @return true if the lib should be included in the webapp classloader.
@@ -255,6 +258,8 @@
private static Field _contextField;
+
+ /* ------------------------------------------------------------ */
/**
* In the case of the generation of a webapp via a jetty context file we
* need a proper classloader to setup the app before we have the
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/JettyContextHandlerServiceTracker.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/ServiceWatcher.java
similarity index 91%
rename from jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/JettyContextHandlerServiceTracker.java
rename to jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/ServiceWatcher.java
index 6bd352d..08dbd4a 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/JettyContextHandlerServiceTracker.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/ServiceWatcher.java
@@ -18,28 +18,18 @@
package org.eclipse.jetty.osgi.boot.internal.webapp;
-import java.io.File;
-import java.io.IOException;
-import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
-import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
-import org.eclipse.jetty.osgi.boot.BundleWebAppProvider;
import org.eclipse.jetty.osgi.boot.JettyBootstrapActivator;
import org.eclipse.jetty.osgi.boot.OSGiServerConstants;
import org.eclipse.jetty.osgi.boot.OSGiWebappConstants;
import org.eclipse.jetty.osgi.boot.ServiceProvider;
-import org.eclipse.jetty.osgi.boot.internal.serverfactory.DefaultJettyAtJettyHomeHelper;
-import org.eclipse.jetty.osgi.boot.internal.serverfactory.IManagedJettyServerRegistry;
-import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
-import org.eclipse.jetty.util.Scanner;
-import org.eclipse.jetty.webapp.WebAppContext;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.FrameworkUtil;
@@ -49,7 +39,7 @@
import org.osgi.util.tracker.ServiceTracker;
/**
- * JettyContextHandlerServiceTracker
+ * ServiceWatcher
*
* When a {@link ContextHandler} is activated as an osgi service we find a jetty deployer
* for it. The ContextHandler could be either a WebAppContext or any other derivative of
@@ -59,9 +49,9 @@
* osgi services. Instead, they can be deployed via manifest headers inside bundles. See
* {@link WebBundleTrackerCustomizer}.
*/
-public class JettyContextHandlerServiceTracker implements ServiceListener
+public class ServiceWatcher implements ServiceListener
{
- private static Logger LOG = Log.getLogger(JettyContextHandlerServiceTracker.class);
+ private static Logger LOG = Log.getLogger(ServiceWatcher.class);
public static final String FILTER = "(objectclass=" + ServiceProvider.class.getName() + ")";
@@ -75,7 +65,7 @@
/**
* @param registry
*/
- public JettyContextHandlerServiceTracker() throws Exception
+ public ServiceWatcher() throws Exception
{
//track all instances of deployers of webapps
Bundle myBundle = FrameworkUtil.getBundle(this.getClass());
@@ -195,6 +185,7 @@
try
{
added = e.getValue().serviceAdded(sr, contextHandler);
+ System.err.println(serverName+" deployed "+contextHandler+": "+added);
if (added && LOG.isDebugEnabled())
LOG.debug("Provider "+e.getValue()+" deployed "+contextHandler);
}
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebBundleTrackerCustomizer.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebBundleTrackerCustomizer.java
deleted file mode 100644
index b8adc65..0000000
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebBundleTrackerCustomizer.java
+++ /dev/null
@@ -1,250 +0,0 @@
-//
-// ========================================================================
-// Copyright (c) 1995-2013 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.osgi.boot.internal.webapp;
-
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-import org.eclipse.jetty.osgi.boot.BundleProvider;
-import org.eclipse.jetty.osgi.boot.OSGiServerConstants;
-import org.eclipse.jetty.osgi.boot.utils.WebappRegistrationCustomizer;
-import org.eclipse.jetty.util.log.Log;
-import org.eclipse.jetty.util.log.Logger;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleEvent;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.ServiceReference;
-import org.osgi.util.tracker.BundleTracker;
-import org.osgi.util.tracker.BundleTrackerCustomizer;
-import org.osgi.util.tracker.ServiceTracker;
-
-/**
- * WebBundleTrackerCustomizer
- *
- *
- * Support bundles that declare a webpp or context directly through headers in their
- * manifest. They will be deployed to the default jetty Server instance.
- *
- * If you wish to deploy a context or webapp to a different jetty Server instance,
- * register your context/webapp as an osgi service, and set the property OSGiServerConstants.MANAGED_JETTY_SERVER_NAME
- * with the name of the Server instance you wish to depoy to.
- *
- * @author hmalphettes
- */
-public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer
-{
- private static final Logger LOG = Log.getLogger(WebBundleTrackerCustomizer.class);
-
- public static Collection<WebappRegistrationCustomizer> JSP_REGISTRATION_HELPERS = new ArrayList<WebappRegistrationCustomizer>();
- public static final String FILTER = "(&(objectclass=" + BundleProvider.class.getName() + ")"+
- "("+OSGiServerConstants.MANAGED_JETTY_SERVER_NAME+"="+OSGiServerConstants.MANAGED_JETTY_SERVER_DEFAULT_NAME+"))";
-
- private ServiceTracker _serviceTracker;
- private BundleTracker _bundleTracker;
-
- /* ------------------------------------------------------------ */
- /**
- * @throws Exception
- */
- public WebBundleTrackerCustomizer ()
- throws Exception
- {
- Bundle myBundle = FrameworkUtil.getBundle(this.getClass());
-
- //track all instances of deployers of webapps/contexts as bundles
- _serviceTracker = new ServiceTracker(myBundle.getBundleContext(), FrameworkUtil.createFilter(FILTER),null) {
- public Object addingService(ServiceReference reference) {
- Object object = super.addingService(reference);
- LOG.debug("Deployer registered {}", reference);
- openBundleTracker();
- return object;
- }
- };
- _serviceTracker.open();
-
- }
-
-
- /* ------------------------------------------------------------ */
- /**
- * A bundle is being added to the <code>BundleTracker</code>.
- *
- * <p>
- * This method is called before a bundle which matched the search parameters
- * of the <code>BundleTracker</code> is added to the
- * <code>BundleTracker</code>. This method should return the object to be
- * tracked for the specified <code>Bundle</code>. The returned object is
- * stored in the <code>BundleTracker</code> and is available from the
- * {@link BundleTracker#getObject(Bundle) getObject} method.
- *
- * @param bundle The <code>Bundle</code> being added to the
- * <code>BundleTracker</code>.
- * @param event The bundle event which caused this customizer method to be
- * called or <code>null</code> if there is no bundle event
- * associated with the call to this method.
- * @return The object to be tracked for the specified <code>Bundle</code>
- * object or <code>null</code> if the specified <code>Bundle</code>
- * object should not be tracked.
- */
- public Object addingBundle(Bundle bundle, BundleEvent event)
- {
- if (bundle.getState() == Bundle.ACTIVE)
- {
- register(bundle);
- }
- else if (bundle.getState() == Bundle.STOPPING)
- {
- unregister(bundle);
- }
- else
- {
- // we should not be called in that state as
- // we are registered only for ACTIVE and STOPPING
- }
- return null;
- }
-
-
- /* ------------------------------------------------------------ */
- /**
- * A bundle tracked by the <code>BundleTracker</code> has been modified.
- *
- * <p>
- * This method is called when a bundle being tracked by the
- * <code>BundleTracker</code> has had its state modified.
- *
- * @param bundle The <code>Bundle</code> whose state has been modified.
- * @param event The bundle event which caused this customizer method to be
- * called or <code>null</code> if there is no bundle event
- * associated with the call to this method.
- * @param object The tracked object for the specified bundle.
- */
- public void modifiedBundle(Bundle bundle, BundleEvent event, Object object)
- {
- // nothing the web-bundle was already track. something changed.
- // we only reload the webapps if the bundle is stopped and restarted.
- if (bundle.getState() == Bundle.STOPPING || bundle.getState() == Bundle.ACTIVE)
- {
- unregister(bundle);
- }
- if (bundle.getState() == Bundle.ACTIVE)
- {
- register(bundle);
- }
- }
-
-
- /* ------------------------------------------------------------ */
- /**
- * A bundle tracked by the <code>BundleTracker</code> has been removed.
- *
- * <p>
- * This method is called after a bundle is no longer being tracked by the
- * <code>BundleTracker</code>.
- *
- * @param bundle The <code>Bundle</code> that has been removed.
- * @param event The bundle event which caused this customizer method to be
- * called or <code>null</code> if there is no bundle event
- * associated with the call to this method.
- * @param object The tracked object for the specified bundle.
- */
- public void removedBundle(Bundle bundle, BundleEvent event, Object object)
- {
- unregister(bundle);
- }
-
-
- /* ------------------------------------------------------------ */
- /**
- * @param bundle
- * @return true if this bundle in indeed a web-bundle.
- */
- private boolean register(Bundle bundle)
- {
- if (bundle == null)
- return false;
-
- //It might be a bundle that we can deploy to our default jetty server instance
- boolean deployed = false;
- Object[] deployers = _serviceTracker.getServices();
- if (deployers != null)
- {
- int i=0;
- while (!deployed && i<deployers.length)
- {
-
- BundleProvider p = (BundleProvider)deployers[i];
- try
- {
- deployed = p.bundleAdded(bundle);
- }
- catch (Exception x)
- {
- LOG.warn("Error deploying bundle for jetty context", x);
- }
- i++;
- }
- }
-
- return deployed;
- }
-
- /* ------------------------------------------------------------ */
- /**
- * @param bundle
- */
- private void unregister(Bundle bundle)
- {
- Object[] deployers = _serviceTracker.getServices();
- boolean undeployed = false;
- if (deployers != null)
- {
- int i=0;
- while (!undeployed && i<deployers.length)
- {
- try
- {
- undeployed = ((BundleProvider)deployers[i++]).bundleRemoved(bundle);
- }
- catch (Exception x)
- {
- LOG.warn("Error undeploying bundle for jetty context", x);
- }
- }
- }
- }
-
- public void setAndOpenWebBundleTracker(BundleTracker bundleTracker) {
- if(_bundleTracker == null) {
- _bundleTracker = bundleTracker;
- LOG.debug("Bundle tracker is set");
- openBundleTracker();
- }
- }
-
- private void openBundleTracker() {
- if(_bundleTracker != null && _serviceTracker.getServices() != null &&
- _serviceTracker.getServices().length > 0) {
- _bundleTracker.open();
- LOG.debug("Bundle tracker has been opened");
- }
- }
-
-}
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleClassLoaderHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleClassLoaderHelper.java
index 4c4382f..ba99ac2 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleClassLoaderHelper.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleClassLoaderHelper.java
@@ -22,6 +22,10 @@
import org.osgi.framework.Bundle;
/**
+ *
+ * BundleClassLoaderHelper
+ *
+ *
* Is there a clean OSGi way to go from the Bundle object to the classloader of
* the Bundle ? You can certainly take a class inside the bundle and get the
* bundle's classloader that way. Getting the classloader directly from the
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleClassLoaderHelperFactory.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleClassLoaderHelperFactory.java
index edcfde0..297f0f3 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleClassLoaderHelperFactory.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleClassLoaderHelperFactory.java
@@ -32,15 +32,19 @@
private static BundleClassLoaderHelperFactory _instance = new BundleClassLoaderHelperFactory();
+
+ /* ------------------------------------------------------------ */
public static BundleClassLoaderHelperFactory getFactory()
{
return _instance;
}
+ /* ------------------------------------------------------------ */
private BundleClassLoaderHelperFactory()
{
}
+ /* ------------------------------------------------------------ */
public BundleClassLoaderHelper getHelper()
{
//use the default
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelper.java
index 0809b72..2abd7a0 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelper.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/BundleFileLocatorHelper.java
@@ -26,6 +26,9 @@
import org.osgi.framework.Bundle;
/**
+ * BundleFileLocatorHelper
+ *
+ *
* From a bundle to its location on the filesystem. Assumes the bundle is not a
* jar.
*
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/EventSender.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/EventSender.java
index 13703fa..c4e06a2 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/EventSender.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/EventSender.java
@@ -21,14 +21,18 @@
import java.util.Dictionary;
import java.util.Hashtable;
-import javax.security.auth.login.FailedLoginException;
-
import org.osgi.framework.Bundle;
import org.osgi.framework.FrameworkUtil;
import org.osgi.framework.ServiceReference;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
+/**
+ * EventSender
+ *
+ * Utility class for emiting OSGi EventAdmin events
+ *
+ */
public class EventSender
{
//OSGi Event Admin events for webapps
@@ -43,6 +47,13 @@
private Bundle _myBundle;
private EventAdmin _eventAdmin;
+
+
+
+ /* ------------------------------------------------------------ */
+ /**
+ *
+ */
private EventSender ()
{
_myBundle = FrameworkUtil.getBundle(EventSender.class);
@@ -50,13 +61,27 @@
if (ref != null)
_eventAdmin = (EventAdmin)_myBundle.getBundleContext().getService(ref);
}
-
+
+
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return
+ */
public static EventSender getInstance()
{
return __instance;
}
+
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param topic
+ * @param wab
+ * @param contextPath
+ */
public void send (String topic, Bundle wab, String contextPath)
{
if (topic==null || wab==null || contextPath==null)
@@ -66,6 +91,14 @@
}
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param topic
+ * @param wab
+ * @param contextPath
+ * @param ex
+ */
public void send (String topic, Bundle wab, String contextPath, Exception ex)
{
if (_eventAdmin == null)
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/FakeURLClassLoader.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/FakeURLClassLoader.java
new file mode 100644
index 0000000..77f8510
--- /dev/null
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/FakeURLClassLoader.java
@@ -0,0 +1,83 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2013 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.osgi.boot.utils;
+
+import java.net.URL;
+import java.net.URLClassLoader;
+
+/**
+ *
+ * FakeURLClassLoader
+ *
+ * A URLClassloader that overrides the getURLs() method to return the list
+ * of urls passed in to the constructor, but otherwise acts as if it has no
+ * urls, which would cause it to delegate to the parent classloader (in this
+ * case an OSGi classloader).
+ *
+ * The main use of this class is with jars containing tlds. Jasper expects a
+ * URL classloader to inspect for jars with tlds.
+ *
+ */
+public class FakeURLClassLoader extends URLClassLoader
+{
+
+ private URL[] _jars;
+
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @param osgiClassLoader
+ * @param jars
+ */
+ public FakeURLClassLoader(ClassLoader osgiClassLoader, URL[] jars)
+ {
+ super(new URL[] {},osgiClassLoader);
+ _jars = jars;
+ }
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @return the jars that contains tlds so that TldLocationsCache or
+ * TldScanner can find them.
+ */
+ @Override
+ public URL[] getURLs()
+ {
+ return _jars;
+ }
+
+
+ /* ------------------------------------------------------------ */
+ /**
+ * @see java.lang.Object#toString()
+ */
+ public String toString()
+ {
+ StringBuilder builder = new StringBuilder();
+
+ if (_jars != null)
+ {
+ for (URL u:_jars)
+ builder.append(" "+u.toString());
+ return builder.toString();
+ }
+ else
+ return super.toString();
+ }
+}
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/OSGiClassLoader.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/OSGiClassLoader.java
index 8850f5e..91f42af 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/OSGiClassLoader.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/OSGiClassLoader.java
@@ -78,8 +78,7 @@
}
if (url == null)
- {
-
+ {
url = _osgiBundleClassLoader.getResource(name);
if (url == null && name.startsWith("/"))
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/TldBundleDiscoverer.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/TldBundleDiscoverer.java
new file mode 100644
index 0000000..bdd6168
--- /dev/null
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/TldBundleDiscoverer.java
@@ -0,0 +1,43 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2013 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.osgi.boot.utils;
+
+import java.net.URL;
+
+import org.eclipse.jetty.deploy.DeploymentManager;
+
+
+/**
+ * TldBundleDiscoverer
+ *
+ * Convert bundles that contain tlds into URL locations for consumption by jasper.
+ */
+public interface TldBundleDiscoverer
+{
+ /**
+ * Find bundles that contain tlds and convert into URL references to their location.
+ *
+ * @param manager
+ * @param fileLocator
+ * @return array of URLs representing locations of tld containing bundles
+ * @throws Exception
+ */
+ URL[] getUrlsForBundlesWithTlds(DeploymentManager manager, BundleFileLocatorHelper fileLocator) throws Exception;
+
+}
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/WebappRegistrationCustomizer.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/WebappRegistrationCustomizer.java
deleted file mode 100644
index 813bff4..0000000
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/WebappRegistrationCustomizer.java
+++ /dev/null
@@ -1,61 +0,0 @@
-//
-// ========================================================================
-// Copyright (c) 1995-2013 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.osgi.boot.utils;
-
-import java.net.URL;
-
-import org.eclipse.jetty.deploy.DeploymentManager;
-
-
-/**
- * Fix various shortcomings with the way jasper parses the tld files.
- */
-public interface WebappRegistrationCustomizer
-{
- /**
- * we could do something a lot more pluggable with a custom header in the
- * manifest or some customer declarative services let's keep it simple for
- * now. hopefully the rest of the world won't need to customize this.
- */
- public static final String CLASS_NAME = "org.eclipse.jetty.osgi.boot.jasper.WebappRegistrationCustomizerImpl";
-
- /**
- * TODO: right now only the jetty-jsp bundle is scanned for common taglibs.
- * Should support a way to plug more bundles that contain taglibs.
- *
- * The jasper TldScanner expects a URLClassloader to parse a jar for the
- * /META-INF/*.tld it may contain. We place the bundles that we know contain
- * such tag-libraries. Please note that it will work if and only if the
- * bundle is a jar (!) Currently we just hardcode the bundle that contains
- * the jstl implemenation.
- *
- * A workaround when the tld cannot be parsed with this method is to copy
- * and paste it inside the WEB-INF of the webapplication where it is used.
- *
- * Support only 2 types of packaging for the bundle: - the bundle is a jar
- * (recommended for runtime.) - the bundle is a folder and contain jars in
- * the root and/or in the lib folder (nice for PDE developement situations)
- * Unsupported: the bundle is a jar that embeds more jars.
- *
- * @return array of URLs
- * @throws Exception
- */
- URL[] getJarsWithTlds(DeploymentManager manager, BundleFileLocatorHelper fileLocator) throws Exception;
-
-}
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultBundleClassLoaderHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultBundleClassLoaderHelper.java
index 9bb074a..ee0d7c2 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultBundleClassLoaderHelper.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultBundleClassLoaderHelper.java
@@ -28,6 +28,9 @@
import org.osgi.framework.Bundle;
/**
+ * DefaultBundleClassLoaderHelper
+ *
+ *
* Default implementation of the BundleClassLoaderHelper. Uses introspection to
* support equinox-3.5 and felix-2.0.0
*/
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java
index 2d31459..7349cd0 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java
@@ -31,11 +31,14 @@
import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
import org.eclipse.jetty.util.URIUtil;
-import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.FileResource;
+import org.eclipse.jetty.util.resource.Resource;
import org.osgi.framework.Bundle;
/**
+ * DefaultFileLocatorHelper
+ *
+ *
* From a bundle to its location on the filesystem. Assumes the bundle is not a
* jar.
*
diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/PackageAdminServiceTracker.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/PackageAdminServiceTracker.java
index 384b392..7ce7551 100644
--- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/PackageAdminServiceTracker.java
+++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/PackageAdminServiceTracker.java
@@ -35,8 +35,14 @@
import org.osgi.service.startlevel.StartLevel;
/**
+ * PackageAdminServiceTracker
+ *
+ *
* When the PackageAdmin service is activated we can look for the fragments
- * attached to this bundle and "activate" them.
+ * attached to this bundle and do a fake "activate" on them.
+ *
+ * See particularly the jetty-osgi-boot-jsp fragment bundle that uses this
+ * facility.
*/
public class PackageAdminServiceTracker implements ServiceListener
{
diff --git a/jetty-server/src/main/config/etc/jetty.xml b/jetty-server/src/main/config/etc/jetty.xml
index 2d9b859..668980e 100644
--- a/jetty-server/src/main/config/etc/jetty.xml
+++ b/jetty-server/src/main/config/etc/jetty.xml
@@ -47,11 +47,6 @@
<Arg name="minThreads" type="int">10</Arg>
<Arg name="maxThreads" type="int">200</Arg>
<Arg name="idleTimeout" type="int">60000</Arg>
- <!-- Arg >
- <New class="org.eclipse.jetty.util.ConcurrentArrayBlockingQueue$Unbounded">
- <Arg type='int'>32</Arg>
- </New>
- </Arg -->
<Set name="detailedDump">false</Set>
</New>
</Arg>
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java
index 2fced56..28fea90 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java
@@ -289,8 +289,9 @@
// If we have a stop timeout
long stopTimeout = getStopTimeout();
- if (stopTimeout > 0 && _stopping!=null)
- _stopping.await(stopTimeout,TimeUnit.MILLISECONDS);
+ CountDownLatch stopping=_stopping;
+ if (stopTimeout > 0 && stopping!=null)
+ stopping.await(stopTimeout,TimeUnit.MILLISECONDS);
_stopping=null;
super.doStop();
@@ -475,7 +476,9 @@
{
_acceptors[_acceptor] = null;
}
- _stopping.countDown();
+ CountDownLatch stopping=_stopping;
+ if (stopping!=null)
+ stopping.countDown();
}
}
}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncNCSARequestLog.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncNCSARequestLog.java
index 047e3b6..9c5d461 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncNCSARequestLog.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncNCSARequestLog.java
@@ -22,7 +22,7 @@
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
-import org.eclipse.jetty.util.ConcurrentArrayBlockingQueue;
+import org.eclipse.jetty.util.BlockingArrayQueue;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@@ -42,7 +42,7 @@
{
this(null,null);
}
-
+
public AsyncNCSARequestLog(BlockingQueue<String> queue)
{
this(null,queue);
@@ -52,12 +52,12 @@
{
this(filename,null);
}
-
+
public AsyncNCSARequestLog(String filename,BlockingQueue<String> queue)
{
super(filename);
if (queue==null)
- queue=new ConcurrentArrayBlockingQueue.Bounded<String>(1024);
+ queue=new BlockingArrayQueue<>(1024);
_queue=queue;
}
@@ -67,7 +67,7 @@
{
setName("AsyncNCSARequestLog@"+Integer.toString(AsyncNCSARequestLog.this.hashCode(),16));
}
-
+
@Override
public void run()
{
@@ -78,7 +78,7 @@
String log = _queue.poll(10,TimeUnit.SECONDS);
if (log!=null)
AsyncNCSARequestLog.super.write(log);
-
+
while(!_queue.isEmpty())
{
log=_queue.poll();
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ShutdownMonitor.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ShutdownMonitor.java
index 6d4f9e1..e789d38 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/ShutdownMonitor.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ShutdownMonitor.java
@@ -146,6 +146,7 @@
{
if (isAlive())
{
+ // TODO why are we reentrant here?
if (DEBUG)
System.err.printf("ShutdownMonitorThread already started");
return; // cannot start it again
@@ -353,7 +354,9 @@
{
if (thread != null && thread.isAlive())
{
- System.err.printf("ShutdownMonitorThread already started");
+ // TODO why are we reentrant here?
+ if (DEBUG)
+ System.err.printf("ShutdownMonitorThread already started");
return; // cannot start it again
}
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
index 3d5fad4..95d307c 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java
@@ -303,7 +303,8 @@
*
* @param virtualHosts
* Array of virtual hosts that this context responds to. A null host name or null/empty array means any hostname is acceptable. Host names may be
- * String representation of IP addresses. Host names may start with '*.' to wildcard one level of names.
+ * String representation of IP addresses. Host names may start with '*.' to wildcard one level of names. Host names may start with '@', in which case they
+ * will match the {@link Connector#getName()} for the request.
*/
public void addVirtualHosts(String[] virtualHosts)
{
@@ -817,8 +818,8 @@
if (!_contextListeners.isEmpty())
{
ServletContextEvent event = new ServletContextEvent(_scontext);
- for (ServletContextListener listener : _contextListeners)
- callContextDestroyed(listener,event);
+ for (int i = _contextListeners.size(); i-->0;)
+ callContextDestroyed(_contextListeners.get(i),event);
}
if (_errorHandler != null)
@@ -1093,20 +1094,15 @@
if (!_requestListeners.isEmpty())
{
final ServletRequestEvent sre = new ServletRequestEvent(_scontext,request);
- ListIterator<ServletRequestListener> iter = _requestListeners.listIterator(_requestListeners.size());
- while (iter.hasNext())
- iter.next();
- while (iter.hasPrevious())
- iter.previous().requestDestroyed(sre);
+ for (int i=_requestListeners.size();i-->0;)
+ _requestListeners.get(i).requestDestroyed(sre);
}
if (!_requestAttributeListeners.isEmpty())
{
ListIterator<ServletRequestAttributeListener> iter = _requestAttributeListeners.listIterator(_requestAttributeListeners.size());
- while(iter.hasNext())
- iter.next();
- while(iter.hasPrevious())
- baseRequest.removeEventListener(iter.previous());
+ for (int i=_requestAttributeListeners.size();i-->0;)
+ baseRequest.removeEventListener(_requestAttributeListeners.get(i));
}
}
}
diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/LowResourcesMonitorTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/LowResourcesMonitorTest.java
index 365a85b..eac1057 100644
--- a/jetty-server/src/test/java/org/eclipse/jetty/server/LowResourcesMonitorTest.java
+++ b/jetty-server/src/test/java/org/eclipse/jetty/server/LowResourcesMonitorTest.java
@@ -80,13 +80,14 @@
@Test
public void testLowOnThreads() throws Exception
{
+ Thread.sleep(1200);
_threadPool.setMaxThreads(_threadPool.getThreads()-_threadPool.getIdleThreads()+10);
Thread.sleep(1200);
Assert.assertFalse(_lowResourcesMonitor.isLowOnResources());
final CountDownLatch latch = new CountDownLatch(1);
- for (int i=0;i<20;i++)
+ for (int i=0;i<100;i++)
{
_threadPool.dispatch(new Runnable()
{
@@ -110,7 +111,6 @@
latch.countDown();
Thread.sleep(1200);
- System.err.println(_threadPool.dump());
Assert.assertFalse(_lowResourcesMonitor.isLowOnResources());
}
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java
index bd5a21b..03752cb 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java
@@ -26,26 +26,22 @@
import java.util.regex.Pattern;
import java.util.zip.Deflater;
import java.util.zip.DeflaterOutputStream;
-import java.util.zip.GZIPOutputStream;
+import javax.servlet.AsyncEvent;
+import javax.servlet.AsyncListener;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
-import javax.servlet.ServletResponseWrapper;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpServletResponseWrapper;
-import org.eclipse.jetty.continuation.Continuation;
-import org.eclipse.jetty.continuation.ContinuationListener;
-import org.eclipse.jetty.continuation.ContinuationSupport;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.servlets.gzip.AbstractCompressedStream;
import org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper;
-import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.servlets.gzip.GzipOutputStream;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@@ -129,6 +125,9 @@
protected int _minGzipSize=256;
protected int _deflateCompressionLevel=Deflater.DEFAULT_COMPRESSION;
protected boolean _deflateNoWrap = true;
+
+ // non-static, as other GzipFilter instances may have different configurations
+ protected final ThreadLocal<Deflater> _deflater = new ThreadLocal<Deflater>();
protected final Set<String> _methods=new HashSet<String>();
protected Set<String> _excludedAgents;
@@ -296,10 +295,10 @@
}
finally
{
- Continuation continuation = ContinuationSupport.getContinuation(request);
- if (continuation.isSuspended() && continuation.isResponseWrapped())
+ if (request.isAsyncStarted())
{
- continuation.addContinuationListener(new ContinuationListenerWaitingForWrappedResponseToFinish(wrappedResponse));
+
+ request.getAsyncContext().addListener(new FinishOnCompleteListener(wrappedResponse));
}
else if (exceptional && !response.isCommitted())
{
@@ -403,64 +402,55 @@
protected CompressedResponseWrapper createWrappedResponse(HttpServletRequest request, HttpServletResponse response, final String compressionType)
{
CompressedResponseWrapper wrappedResponse = null;
- if (compressionType==null)
+ wrappedResponse = new CompressedResponseWrapper(request,response)
{
- wrappedResponse = new CompressedResponseWrapper(request,response)
+ @Override
+ protected AbstractCompressedStream newCompressedStream(HttpServletRequest request, HttpServletResponse response) throws IOException
{
- @Override
- protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
+ return new AbstractCompressedStream(compressionType,request,this,_vary)
{
- return new AbstractCompressedStream(null,request,this,_vary)
+ private Deflater _allocatedDeflater;
+
+ @Override
+ protected DeflaterOutputStream createStream() throws IOException
{
- @Override
- protected DeflaterOutputStream createStream() throws IOException
+ if (compressionType == null)
{
return null;
}
- };
- }
- };
- }
- else if (compressionType.equals(GZIP))
- {
- wrappedResponse = new CompressedResponseWrapper(request,response)
- {
- @Override
- protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
- {
- return new AbstractCompressedStream(compressionType,request,this,_vary)
- {
- @Override
- protected DeflaterOutputStream createStream() throws IOException
+
+ // acquire deflater instance
+ _allocatedDeflater = _deflater.get();
+ if (_allocatedDeflater==null)
+ _allocatedDeflater = new Deflater(_deflateCompressionLevel,_deflateNoWrap);
+ else
{
- return new GZIPOutputStream(_response.getOutputStream(),_bufferSize);
+ _deflater.remove();
+ _allocatedDeflater.reset();
}
- };
- }
- };
- }
- else if (compressionType.equals(DEFLATE))
- {
- wrappedResponse = new CompressedResponseWrapper(request,response)
- {
- @Override
- protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
- {
- return new AbstractCompressedStream(compressionType,request,this,_vary)
- {
- @Override
- protected DeflaterOutputStream createStream() throws IOException
+
+ switch (compressionType)
{
- return new DeflaterOutputStream(_response.getOutputStream(),new Deflater(_deflateCompressionLevel,_deflateNoWrap));
+ case GZIP:
+ return new GzipOutputStream(_response.getOutputStream(),_allocatedDeflater,_bufferSize);
+ case DEFLATE:
+ return new DeflaterOutputStream(_response.getOutputStream(),_allocatedDeflater,_bufferSize);
}
- };
- }
- };
- }
- else
- {
- throw new IllegalStateException(compressionType + " not supported");
- }
+ throw new IllegalStateException(compressionType + " not supported");
+ }
+
+ @Override
+ public void finish() throws IOException
+ {
+ super.finish();
+ if (_allocatedDeflater != null && _deflater.get() == null)
+ {
+ _deflater.set(_allocatedDeflater);
+ }
+ }
+ };
+ }
+ };
configureWrappedResponse(wrappedResponse);
return wrappedResponse;
}
@@ -472,18 +462,18 @@
wrappedResponse.setMinCompressSize(_minGzipSize);
}
- private class ContinuationListenerWaitingForWrappedResponseToFinish implements ContinuationListener
+ private class FinishOnCompleteListener implements AsyncListener
{
private CompressedResponseWrapper wrappedResponse;
- public ContinuationListenerWaitingForWrappedResponseToFinish(CompressedResponseWrapper wrappedResponse)
+ public FinishOnCompleteListener(CompressedResponseWrapper wrappedResponse)
{
this.wrappedResponse = wrappedResponse;
}
@Override
- public void onComplete(Continuation continuation)
- {
+ public void onComplete(AsyncEvent event) throws IOException
+ {
try
{
wrappedResponse.finish();
@@ -495,7 +485,17 @@
}
@Override
- public void onTimeout(Continuation continuation)
+ public void onTimeout(AsyncEvent event) throws IOException
+ {
+ }
+
+ @Override
+ public void onError(AsyncEvent event) throws IOException
+ {
+ }
+
+ @Override
+ public void onStartAsync(AsyncEvent event) throws IOException
{
}
}
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHandler.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHandler.java
index 3ea1c2a..ec125b9 100644
--- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHandler.java
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipHandler.java
@@ -29,13 +29,12 @@
import java.util.zip.DeflaterOutputStream;
import java.util.zip.GZIPOutputStream;
+import javax.servlet.AsyncEvent;
+import javax.servlet.AsyncListener;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
-import org.eclipse.jetty.continuation.Continuation;
-import org.eclipse.jetty.continuation.ContinuationListener;
-import org.eclipse.jetty.continuation.ContinuationSupport;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.HandlerWrapper;
@@ -265,12 +264,28 @@
}
finally
{
- Continuation continuation = ContinuationSupport.getContinuation(request);
- if (continuation.isSuspended() && continuation.isResponseWrapped())
+ if (request.isAsyncStarted())
{
- continuation.addContinuationListener(new ContinuationListener()
+ request.getAsyncContext().addListener(new AsyncListener()
{
- public void onComplete(Continuation continuation)
+
+ @Override
+ public void onTimeout(AsyncEvent event) throws IOException
+ {
+ }
+
+ @Override
+ public void onStartAsync(AsyncEvent event) throws IOException
+ {
+ }
+
+ @Override
+ public void onError(AsyncEvent event) throws IOException
+ {
+ }
+
+ @Override
+ public void onComplete(AsyncEvent event) throws IOException
{
try
{
@@ -281,9 +296,6 @@
LOG.warn(e);
}
}
-
- public void onTimeout(Continuation continuation)
- {}
});
}
else if (exceptional && !response.isCommitted())
diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipOutputStream.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipOutputStream.java
new file mode 100644
index 0000000..8f20c2f
--- /dev/null
+++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/gzip/GzipOutputStream.java
@@ -0,0 +1,71 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2013 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.servlets.gzip;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.zip.CRC32;
+import java.util.zip.Deflater;
+import java.util.zip.DeflaterOutputStream;
+
+/**
+ * Reimplementation of {@link java.util.zip.GZIPOutputStream} that supports reusing a {@link Deflater} instance.
+ */
+public class GzipOutputStream extends DeflaterOutputStream
+{
+
+ private final static byte[] GZIP_HEADER = new byte[]
+ { (byte)0x1f, (byte)0x8b, Deflater.DEFLATED, 0, 0, 0, 0, 0, 0, 0 };
+
+ private final CRC32 _crc = new CRC32();
+
+ public GzipOutputStream(OutputStream out, Deflater deflater, int size) throws IOException
+ {
+ super(out,deflater,size);
+ out.write(GZIP_HEADER);
+ }
+
+ public synchronized void write(byte[] buf, int off, int len) throws IOException
+ {
+ super.write(buf,off,len);
+ _crc.update(buf,off,len);
+ }
+
+ public void finish() throws IOException
+ {
+ if (!def.finished())
+ {
+ super.finish();
+ byte[] trailer = new byte[8];
+ writeInt((int)_crc.getValue(),trailer,0);
+ writeInt(def.getTotalIn(),trailer,4);
+ out.write(trailer);
+ }
+ }
+
+ private void writeInt(int i, byte[] buf, int offset)
+ {
+ int o = offset;
+ buf[o++] = (byte)(i & 0xFF);
+ buf[o++] = (byte)((i >>> 8) & 0xFF);
+ buf[o++] = (byte)((i >>> 16) & 0xFF);
+ buf[o++] = (byte)((i >>> 24) & 0xFF);
+ }
+
+}
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PipelineHelper.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PipelineHelper.java
index 8e2fea7..95f0a23 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PipelineHelper.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PipelineHelper.java
@@ -219,8 +219,8 @@
int val = inputStream.read();
try
{
- if (left % 10 == 0)
- Thread.sleep(1);
+ if (left % 1000 == 0)
+ Thread.sleep(10);
}
catch (InterruptedException e)
{
diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/QoSFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/QoSFilterTest.java
index f9296ce..61ff30a 100644
--- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/QoSFilterTest.java
+++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/QoSFilterTest.java
@@ -18,7 +18,6 @@
package org.eclipse.jetty.servlets;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
@@ -42,7 +41,9 @@
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
+import org.hamcrest.Matchers;
import org.junit.After;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@@ -91,8 +92,10 @@
_doneRequests.await(10,TimeUnit.SECONDS);
- assertFalse("TEST WAS NOT PARALLEL ENOUGH!",TestServlet.__maxSleepers<=MAX_QOS);
- assertTrue(TestServlet.__maxSleepers<=NUM_CONNECTIONS);
+ if (TestServlet.__maxSleepers<=MAX_QOS)
+ LOG.warn("TEST WAS NOT PARALLEL ENOUGH!");
+ else
+ Assert.assertThat(TestServlet.__maxSleepers,Matchers.lessThanOrEqualTo(NUM_CONNECTIONS));
}
@Test
@@ -109,8 +112,10 @@
}
_doneRequests.await(10,TimeUnit.SECONDS);
- assertFalse("TEST WAS NOT PARALLEL ENOUGH!",TestServlet.__maxSleepers<MAX_QOS);
- assertTrue(TestServlet.__maxSleepers==MAX_QOS);
+ if (TestServlet.__maxSleepers<MAX_QOS)
+ LOG.warn("TEST WAS NOT PARALLEL ENOUGH!");
+ else
+ Assert.assertEquals(TestServlet.__maxSleepers,MAX_QOS);
}
@Test
@@ -126,8 +131,10 @@
}
_doneRequests.await(20,TimeUnit.SECONDS);
- assertFalse("TEST WAS NOT PARALLEL ENOUGH!",TestServlet.__maxSleepers<MAX_QOS);
- assertTrue(TestServlet.__maxSleepers<=MAX_QOS);
+ if (TestServlet.__maxSleepers<MAX_QOS)
+ LOG.warn("TEST WAS NOT PARALLEL ENOUGH!");
+ else
+ Assert.assertEquals(TestServlet.__maxSleepers,MAX_QOS);
}
class Worker implements Runnable {
@@ -137,6 +144,7 @@
_num = num;
}
+ @Override
public void run()
{
for (int i=0;i<NUM_LOOPS;i++)
@@ -170,6 +178,7 @@
_num = num;
}
+ @Override
public void run()
{
URL url=null;
@@ -198,6 +207,7 @@
private static int __sleepers;
private static int __maxSleepers;
+ @Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
try
@@ -232,6 +242,7 @@
public static class QoSFilter2 extends QoSFilter
{
+ @Override
public int getPriority(ServletRequest request)
{
String p = request.getParameter("priority");
diff --git a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java
index c642050..30dc870 100644
--- a/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java
+++ b/jetty-spdy/spdy-core/src/main/java/org/eclipse/jetty/spdy/StandardSession.java
@@ -110,7 +110,9 @@
private final AtomicBoolean goAwaySent = new AtomicBoolean();
private final AtomicBoolean goAwayReceived = new AtomicBoolean();
private final AtomicInteger lastStreamId = new AtomicInteger();
+ private final AtomicInteger localStreamCount = new AtomicInteger(0);
private final FlowControlStrategy flowControlStrategy;
+ private volatile int maxConcurrentLocalStreams = -1;
private boolean flushing;
private Throwable failure;
@@ -181,6 +183,8 @@
// TODO: for SPDYv3 we need to support the "slot" argument
SynStreamFrame synStream = new SynStreamFrame(version, synInfo.getFlags(), streamId, associatedStreamId, synInfo.getPriority(), (short)0, synInfo.getHeaders());
IStream stream = createStream(synStream, listener, true, promise);
+ if (stream == null)
+ return;
generateAndEnqueueControlFrame(stream, synStream, synInfo.getTimeout(), synInfo.getUnit(), stream);
}
flush();
@@ -240,7 +244,6 @@
@Override
public PingResultInfo ping(PingInfo pingInfo) throws ExecutionException, InterruptedException, TimeoutException
{
- //TODO: find a better name for PingResultInfo
FuturePromise<PingResultInfo> result = new FuturePromise<>();
ping(pingInfo, result);
if (pingInfo.getTimeout() > 0)
@@ -535,27 +538,45 @@
}
int streamId = stream.getId();
+
+ if (local)
+ {
+ while (true)
+ {
+ int oldStreamCountValue = localStreamCount.get();
+ int maxConcurrentStreams = maxConcurrentLocalStreams;
+ if (maxConcurrentStreams > -1 && oldStreamCountValue >= maxConcurrentStreams)
+ {
+ String message = String.format("Max concurrent local streams (%d) exceeded.",
+ maxConcurrentStreams);
+ LOG.debug(message);
+ promise.failed(new SPDYException(message));
+ return null;
+ }
+ if (localStreamCount.compareAndSet(oldStreamCountValue, oldStreamCountValue + 1))
+ break;
+ }
+ }
+
if (streams.putIfAbsent(streamId, stream) != null)
{
+ String message = "Duplicate stream id " + streamId;
+ IllegalStateException duplicateIdException = new IllegalStateException(message);
+ promise.failed(duplicateIdException);
if (local)
- throw new IllegalStateException("Duplicate stream id " + streamId);
+ {
+ localStreamCount.decrementAndGet();
+ throw duplicateIdException;
+ }
RstInfo rstInfo = new RstInfo(streamId, StreamStatus.PROTOCOL_ERROR);
LOG.debug("Duplicate stream, {}", rstInfo);
- try
- {
- rst(rstInfo);
- }
- catch (InterruptedException | ExecutionException | TimeoutException e)
- {
- e.printStackTrace(); // TODO: really catch???
- }
+ rst(rstInfo, new Callback.Adapter()); // We don't care (too much) if the reset fails.
return null;
}
else
{
LOG.debug("Created {}", stream);
- if (local)
- notifyStreamCreated(stream);
+ notifyStreamCreated(stream);
return stream;
}
}
@@ -590,10 +611,15 @@
IStream removed = streams.remove(stream.getId());
if (removed != null)
+ {
assert removed == stream;
- LOG.debug("Removed {}", stream);
- notifyStreamClosed(stream);
+ if (streamIds.get() % 2 == stream.getId() % 2)
+ localStreamCount.decrementAndGet();
+
+ LOG.debug("Removed {}", stream);
+ notifyStreamClosed(stream);
+ }
}
private void notifyStreamClosed(IStream stream)
@@ -666,6 +692,13 @@
setWindowSize(windowSize);
LOG.debug("Updated session window size to {}", windowSize);
}
+ Settings.Setting maxConcurrentStreamsSetting = frame.getSettings().get(Settings.ID.MAX_CONCURRENT_STREAMS);
+ if (maxConcurrentStreamsSetting != null)
+ {
+ int maxConcurrentStreamsValue = maxConcurrentStreamsSetting.value();
+ maxConcurrentLocalStreams = maxConcurrentStreamsValue;
+ LOG.debug("Updated session maxConcurrentLocalStreams to {}", maxConcurrentStreamsValue);
+ }
SettingsInfo settingsInfo = new SettingsInfo(frame.getSettings(), frame.isClearPersisted());
notifyOnSettings(listener, settingsInfo);
flush();
diff --git a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardSessionTest.java b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardSessionTest.java
index 44e56ff..813fb0c 100644
--- a/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardSessionTest.java
+++ b/jetty-spdy/spdy-core/src/test/java/org/eclipse/jetty/spdy/StandardSessionTest.java
@@ -18,15 +18,6 @@
package org.eclipse.jetty.spdy;
-import static org.hamcrest.Matchers.greaterThan;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.not;
-import static org.junit.Assert.assertThat;
-import static org.mockito.Matchers.any;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.util.HashSet;
@@ -47,12 +38,14 @@
import org.eclipse.jetty.spdy.api.RstInfo;
import org.eclipse.jetty.spdy.api.SPDY;
import org.eclipse.jetty.spdy.api.Session;
+import org.eclipse.jetty.spdy.api.Settings;
import org.eclipse.jetty.spdy.api.Stream;
import org.eclipse.jetty.spdy.api.StreamFrameListener;
import org.eclipse.jetty.spdy.api.StreamStatus;
import org.eclipse.jetty.spdy.api.StringDataInfo;
import org.eclipse.jetty.spdy.api.SynInfo;
import org.eclipse.jetty.spdy.frames.DataFrame;
+import org.eclipse.jetty.spdy.frames.SettingsFrame;
import org.eclipse.jetty.spdy.frames.SynReplyFrame;
import org.eclipse.jetty.spdy.frames.SynStreamFrame;
import org.eclipse.jetty.spdy.generator.Generator;
@@ -74,6 +67,15 @@
import org.mockito.runners.MockitoJUnitRunner;
import org.mockito.stubbing.Answer;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
@RunWith(MockitoJUnitRunner.class)
public class StandardSessionTest
{
@@ -457,7 +459,30 @@
stream.headers(new HeadersInfo(headers, true));
verify(controller, times(3)).write(any(ByteBuffer.class), any(Callback.class));
+ }
+ @Test
+ public void testMaxConcurrentStreams() throws InterruptedException
+ {
+ final CountDownLatch failedBecauseMaxConcurrentStreamsExceeded = new CountDownLatch(1);
+
+ Settings settings = new Settings();
+ settings.put(new Settings.Setting(Settings.ID.MAX_CONCURRENT_STREAMS, 0));
+ SettingsFrame settingsFrame = new SettingsFrame(VERSION, (byte)0, settings);
+ session.onControlFrame(settingsFrame);
+
+ PushSynInfo pushSynInfo = new PushSynInfo(1, new PushInfo(new Fields(), false));
+ session.syn(pushSynInfo, null, new Promise.Adapter<Stream>()
+ {
+ @Override
+ public void failed(Throwable x)
+ {
+ failedBecauseMaxConcurrentStreamsExceeded.countDown();
+ }
+ });
+
+ assertThat("Opening push stream failed because maxConcurrentStream is exceeded",
+ failedBecauseMaxConcurrentStreamsExceeded.await(5, TimeUnit.SECONDS), is(true));
}
@Test
diff --git a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java
index f52c875..099f736 100644
--- a/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java
+++ b/jetty-spdy/spdy-http-server/src/test/java/org/eclipse/jetty/spdy/server/http/ReferrerPushStrategyTest.java
@@ -101,14 +101,14 @@
@Test
public void testPushHeadersAreValid() throws Exception
{
- sendMainRequestAndCSSRequest();
+ sendMainRequestAndCSSRequest(null);
run2ndClientRequests(true, true);
}
@Test
public void testClientResetsPushStreams() throws Exception
{
- sendMainRequestAndCSSRequest();
+ sendMainRequestAndCSSRequest(null);
final CountDownLatch pushDataLatch = new CountDownLatch(1);
final CountDownLatch pushSynHeadersValid = new CountDownLatch(1);
Session session = startClient(version, serverAddress, null);
@@ -125,14 +125,14 @@
public void testUserAgentBlackList() throws Exception
{
pushStrategy.setUserAgentBlacklist(Arrays.asList(".*(?i)firefox/16.*"));
- sendMainRequestAndCSSRequest();
+ sendMainRequestAndCSSRequest(null);
run2ndClientRequests(false, false);
}
@Test
public void testReferrerPushPeriod() throws Exception
{
- Session session = sendMainRequestAndCSSRequest();
+ Session session = sendMainRequestAndCSSRequest(null);
// Sleep for pushPeriod This should prevent application.js from being mapped as pushResource
Thread.sleep(referrerPushPeriod + 1);
@@ -148,13 +148,38 @@
connector.addConnectionFactory(defaultFactory);
connector.setDefaultProtocol(defaultFactory.getProtocol()); // TODO I don't think this is right
- Session session = sendMainRequestAndCSSRequest();
+ Session session = sendMainRequestAndCSSRequest(null);
sendRequest(session, associatedJSRequestHeaders, null, null);
run2ndClientRequests(false, true);
}
+ @Test
+ public void testMaxConcurrentStreamsToDisablePush() throws Exception
+ {
+ final CountDownLatch pushReceivedLatch = new CountDownLatch(1);
+ Session session = sendMainRequestAndCSSRequest(new SessionFrameListener.Adapter()
+ {
+ @Override
+ public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
+ {
+ pushReceivedLatch.countDown();
+ return null;
+ }
+ });
+
+// Settings settings = new Settings();
+// settings.put(new Settings.Setting(Settings.ID.MAX_CONCURRENT_STREAMS, 0));
+// SettingsInfo settingsInfo = new SettingsInfo(settings);
+//
+// session.settings(settingsInfo);
+
+ sendRequest(session, mainRequestHeaders, null, null);
+
+ assertThat(pushReceivedLatch.await(1, TimeUnit.SECONDS), is(false));
+ }
+
private InetSocketAddress createServer() throws Exception
{
GzipHandler gzipHandler = new GzipHandler();
@@ -177,9 +202,9 @@
return startHTTPServer(version, gzipHandler);
}
- private Session sendMainRequestAndCSSRequest() throws Exception
+ private Session sendMainRequestAndCSSRequest(SessionFrameListener sessionFrameListener) throws Exception
{
- Session session = startClient(version, serverAddress, null);
+ Session session = startClient(version, serverAddress, sessionFrameListener);
sendRequest(session, mainRequestHeaders, null, null);
sendRequest(session, associatedCSSRequestHeaders, null, null);
@@ -197,7 +222,8 @@
@Override
public StreamFrameListener onPush(Stream stream, PushInfo pushInfo)
{
- validateHeaders(pushInfo.getHeaders(), pushSynHeadersValid);
+ if (pushSynHeadersValid != null)
+ validateHeaders(pushInfo.getHeaders(), pushSynHeadersValid);
assertThat("Stream is unidirectional", stream.isUnidirectional(), is(true));
assertThat("URI header ends with css", pushInfo.getHeaders().get(HTTPSPDYHeader.URI.name(version))
diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/AbstractTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/AbstractTest.java
index 08625cc..cdbe2ba 100644
--- a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/AbstractTest.java
+++ b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/AbstractTest.java
@@ -53,13 +53,15 @@
}
};
+ protected final short version = SPDY.V2;
+
protected Server server;
protected SPDYClient.Factory clientFactory;
protected SPDYServerConnector connector;
protected InetSocketAddress startServer(ServerSessionFrameListener listener) throws Exception
{
- return startServer(SPDY.V2, listener);
+ return startServer(version, listener);
}
protected InetSocketAddress startServer(short version, ServerSessionFrameListener listener) throws Exception
@@ -99,7 +101,7 @@
protected Session startClient(InetSocketAddress socketAddress, SessionFrameListener listener) throws Exception
{
- return startClient(SPDY.V2, socketAddress, listener);
+ return startClient(version, socketAddress, listener);
}
protected Session startClient(short version, InetSocketAddress socketAddress, SessionFrameListener listener) throws Exception
diff --git a/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/MaxConcurrentStreamTest.java b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/MaxConcurrentStreamTest.java
new file mode 100644
index 0000000..5c74ca3
--- /dev/null
+++ b/jetty-spdy/spdy-server/src/test/java/org/eclipse/jetty/spdy/server/MaxConcurrentStreamTest.java
@@ -0,0 +1,120 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2013 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.spdy.server;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
+import org.eclipse.jetty.spdy.api.DataInfo;
+import org.eclipse.jetty.spdy.api.ReplyInfo;
+import org.eclipse.jetty.spdy.api.Session;
+import org.eclipse.jetty.spdy.api.SessionFrameListener;
+import org.eclipse.jetty.spdy.api.Settings;
+import org.eclipse.jetty.spdy.api.SettingsInfo;
+import org.eclipse.jetty.spdy.api.Stream;
+import org.eclipse.jetty.spdy.api.StreamFrameListener;
+import org.eclipse.jetty.spdy.api.SynInfo;
+import org.eclipse.jetty.spdy.api.server.ServerSessionFrameListener;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.Fields;
+import org.junit.Test;
+
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+public class MaxConcurrentStreamTest extends AbstractTest
+{
+ @Test
+ public void testMaxConcurrentStreamsSetByServer() throws Exception, ExecutionException
+ {
+ final CountDownLatch settingsReceivedLatch = new CountDownLatch(1);
+ final CountDownLatch dataReceivedLatch = new CountDownLatch(1);
+
+ Session session = startClient(startServer(new ServerSessionFrameListener.Adapter()
+ {
+ @Override
+ public void onConnect(Session session)
+ {
+ Settings settings = new Settings();
+ settings.put(new Settings.Setting(Settings.ID.MAX_CONCURRENT_STREAMS, 1));
+ try
+ {
+ session.settings(new SettingsInfo(settings));
+ }
+ catch (ExecutionException | InterruptedException | TimeoutException e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
+ {
+ try
+ {
+ stream.reply(new ReplyInfo(true));
+ }
+ catch (ExecutionException | InterruptedException | TimeoutException e)
+ {
+ e.printStackTrace();
+ }
+ return new StreamFrameListener.Adapter()
+ {
+ @Override
+ public void onData(Stream stream, DataInfo dataInfo)
+ {
+ dataReceivedLatch.countDown();
+ }
+ };
+ }
+ }), new SessionFrameListener.Adapter()
+ {
+ @Override
+ public void onSettings(Session session, SettingsInfo settingsInfo)
+ {
+ settingsReceivedLatch.countDown();
+ }
+ });
+
+ assertThat("Settings frame received", settingsReceivedLatch.await(5, TimeUnit.SECONDS), is(true));
+
+ SynInfo synInfo = new SynInfo(new Fields(), false);
+ Stream stream = session.syn(synInfo, null);
+
+ boolean failed = false;
+ try
+ {
+ session.syn(synInfo, null);
+ }
+ catch (ExecutionException | InterruptedException | TimeoutException e)
+ {
+ failed = true;
+ }
+
+ assertThat("Opening second stream failed", failed, is(true));
+
+ stream.data(new ByteBufferDataInfo(BufferUtil.EMPTY_BUFFER, true));
+ assertThat("Data has been received on first stream.", dataReceivedLatch.await(5, TimeUnit.SECONDS), is(true));
+
+ session.syn(synInfo, null);
+ }
+}
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/AbstractTrie.java b/jetty-util/src/main/java/org/eclipse/jetty/util/AbstractTrie.java
index dd2f53c..a9cb827 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/AbstractTrie.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/AbstractTrie.java
@@ -57,16 +57,6 @@
return get(s,0,s.length());
}
-
- @Override
- public V get(ByteBuffer b, int offset, int len)
- {
- b=b.duplicate();
- b.position(b.position()+offset);
- b.limit(b.position()+len);
- return get(BufferUtil.toString(b,StringUtil.__ISO_8859_1_CHARSET));
- }
-
@Override
public V get(ByteBuffer b)
{
@@ -86,15 +76,6 @@
}
@Override
- public V getBest(ByteBuffer b, int offset, int len)
- {
- b=b.duplicate();
- b.position(b.position()+offset);
- b.limit(b.position()+len);
- return getBest(BufferUtil.toString(b,StringUtil.__ISO_8859_1_CHARSET));
- }
-
- @Override
public boolean isCaseInsensitive()
{
return _caseInsensitive;
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java
index 7c92ac5..312bd96 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/ArrayTernaryTrie.java
@@ -18,6 +18,7 @@
package org.eclipse.jetty.util;
+import java.nio.ByteBuffer;
import java.util.HashSet;
import java.util.Set;
@@ -194,6 +195,45 @@
}
+ @Override
+ public V get(ByteBuffer b, int offset, int length)
+ {
+ int t = _tree[EQ];
+ int len = length;
+ int i=0;
+ offset+=b.position();
+
+ while(i<len)
+ {
+ byte c=(byte)(b.get(offset+i++)&0x7f);
+ if(isCaseInsensitive())
+ c=(byte)StringUtil.lowercases[c];
+
+ while (true)
+ {
+ int row = ROW_SIZE*t;
+ char n=_tree[row];
+ int diff=n-c;
+
+ if (diff==0)
+ {
+ if (i==len)
+ return (V)_value[t];
+ t=_tree[row+EQ];
+ if (t==0)
+ return null;
+ break;
+ }
+
+ t=_tree[row+((diff<0)?LO:HI)];
+ if (t==0)
+ return null;
+ }
+ }
+
+ return null;
+ }
+
/* ------------------------------------------------------------ */
@Override
public V getBest(String s)
@@ -248,6 +288,95 @@
}
+ /* ------------------------------------------------------------ */
+ @Override
+ public V getBest(ByteBuffer b, int offset, int len)
+ {
+ if (b.hasArray())
+ return getBest(_tree[EQ],b.array(),b.arrayOffset()+b.position()+offset,len);
+ return getBest(_tree[EQ],b,offset,len);
+ }
+
+ /* ------------------------------------------------------------ */
+ private V getBest(int t,byte[] b, int offset, int len)
+ {
+ int node=0;
+ for(int i=0; t!=0 && i<len; i++)
+ {
+ byte c=(byte)(b[offset+i]&0x7f);
+ if(isCaseInsensitive())
+ c=(byte)StringUtil.lowercases[c];
+
+ while (t!=0)
+ {
+ int row = ROW_SIZE*t;
+ char n=_tree[row];
+ int diff=n-c;
+
+ if (diff==0)
+ {
+ node=t;
+ t=_tree[row+EQ];
+
+ // if this node is a match, recurse to remember
+ if (_key[node]!=null)
+ {
+ V best=getBest(t,b,offset+i+1,len-i-1);
+ if (best!=null)
+ return best;
+ return (V)_value[node];
+ }
+
+ break;
+ }
+
+ t=_tree[row+((diff<0)?LO:HI)];
+ }
+ }
+ return null;
+ }
+
+ /* ------------------------------------------------------------ */
+ private V getBest(int t,ByteBuffer b, int offset, int len)
+ {
+ int node=0;
+ int o= offset+b.position();
+
+ for(int i=0; t!=0 && i<len; i++)
+ {
+ byte c=(byte)(b.get(o+i)&0x7f);
+ if(isCaseInsensitive())
+ c=(byte)StringUtil.lowercases[c];
+
+ while (t!=0)
+ {
+ int row = ROW_SIZE*t;
+ char n=_tree[row];
+ int diff=n-c;
+
+ if (diff==0)
+ {
+ node=t;
+ t=_tree[row+EQ];
+
+ // if this node is a match, recurse to remember
+ if (_key[node]!=null)
+ {
+ V best=getBest(t,b,offset+i+1,len-i-1);
+ if (best!=null)
+ return best;
+ return (V)_value[node];
+ }
+
+ break;
+ }
+
+ t=_tree[row+((diff<0)?LO:HI)];
+ }
+ }
+ return null;
+ }
+
@Override
public String toString()
{
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java
index dcfa977..6aa3287 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java
@@ -89,9 +89,9 @@
setMaxThreads(maxThreads);
setIdleTimeout(idleTimeout);
setStopTimeout(5000);
-
+
if (queue==null)
- queue=new BlockingArrayQueue<Runnable>(_minThreads, _minThreads);// TODO ConcurrentArrayBlockingQueue.Unbounded<Runnable>();
+ queue=new BlockingArrayQueue<>(_minThreads, _minThreads);
_jobs=queue;
}
diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/QueueBenchmarkTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/QueueBenchmarkTest.java
new file mode 100644
index 0000000..750c288
--- /dev/null
+++ b/jetty-util/src/test/java/org/eclipse/jetty/util/QueueBenchmarkTest.java
@@ -0,0 +1,224 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2013 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.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import org.eclipse.jetty.toolchain.test.AdvancedRunner;
+import org.eclipse.jetty.toolchain.test.annotation.Stress;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AdvancedRunner.class)
+public class QueueBenchmarkTest
+{
+ private static final Logger logger = Log.getLogger(QueueBenchmarkTest.class);
+ private static final Runnable ELEMENT = new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ }
+ };
+ private static final Runnable END = new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ }
+ };
+
+ @Stress("High CPU")
+ @Test
+ public void testQueues() throws Exception
+ {
+ int cores = Runtime.getRuntime().availableProcessors();
+ Assume.assumeTrue(cores > 1);
+
+ final int readers = cores / 2;
+ final int writers = readers;
+ final int iterations = 16 * 1024 * 1024;
+
+ final List<Queue<Runnable>> queues = new ArrayList<>();
+ queues.add(new ConcurrentArrayQueue<Runnable>()); // Jetty lock-free queue, allocating array blocks
+ queues.add(new ConcurrentLinkedQueue<Runnable>()); // JDK lock-free queue, allocating nodes
+ queues.add(new ArrayBlockingQueue<Runnable>(iterations * writers)); // JDK lock-based, circular array queue
+ queues.add(new BlockingArrayQueue<Runnable>(iterations * writers)); // Jetty lock-based, circular array queue
+
+ testQueues(readers, writers, iterations, queues, false);
+ }
+
+ @Stress("High CPU")
+ @Test
+ public void testBlockingQueues() throws Exception
+ {
+ int cores = Runtime.getRuntime().availableProcessors();
+ Assume.assumeTrue(cores > 1);
+
+ final int readers = cores / 2;
+ final int writers = readers;
+ final int iterations = 16 * 1024 * 1024;
+
+ final List<Queue<Runnable>> queues = new ArrayList<>();
+ queues.add(new ConcurrentArrayBlockingQueue.Unbounded<Runnable>());
+ queues.add(new ConcurrentArrayBlockingQueue.Bounded<Runnable>(iterations * writers));
+ queues.add(new LinkedBlockingQueue<Runnable>());
+ queues.add(new ArrayBlockingQueue<Runnable>(iterations * writers));
+ queues.add(new BlockingArrayQueue<Runnable>(iterations * writers));
+
+ testQueues(readers, writers, iterations, queues, true);
+ }
+
+ private void testQueues(final int readers, final int writers, final int iterations, List<Queue<Runnable>> queues, final boolean blocking) throws Exception
+ {
+ final int runs = 8;
+ int threads = readers + writers;
+ final CyclicBarrier barrier = new CyclicBarrier(threads + 1);
+
+ for (final Queue<Runnable> queue : queues)
+ {
+ for (int r = 0; r < runs; ++r)
+ {
+ for (int i = 0; i < readers; ++i)
+ {
+ Thread thread = new Thread()
+ {
+ @Override
+ public void run()
+ {
+ await(barrier);
+ consume(queue, writers, blocking);
+ await(barrier);
+ }
+ };
+ thread.start();
+ }
+ for (int i = 0; i < writers; ++i)
+ {
+ Thread thread = new Thread()
+ {
+ @Override
+ public void run()
+ {
+ await(barrier);
+ produce(queue, readers, iterations);
+ await(barrier);
+ }
+ };
+ thread.start();
+ }
+
+ await(barrier);
+ long begin = System.nanoTime();
+ await(barrier);
+ long end = System.nanoTime();
+ long elapsed = TimeUnit.NANOSECONDS.toMillis(end - begin);
+ logger.info("{} Readers/Writers: {}/{} => {} ms", queue.getClass().getSimpleName(), readers, writers, elapsed);
+ }
+ }
+ }
+
+ private static void consume(Queue<Runnable> queue, int writers, boolean blocking)
+ {
+ while (true)
+ {
+ Runnable element = blocking ? take(queue) : poll(queue);
+ if (element == END)
+ if (--writers == 0)
+ break;
+ }
+ }
+
+ private static void produce(Queue<Runnable> queue, int readers, int iterations)
+ {
+ for (int i = 0; i < iterations; ++i)
+ append(queue, ELEMENT);
+ for (int i = 0; i < readers; ++i)
+ append(queue, END);
+ }
+
+ private static void append(Queue<Runnable> queue, Runnable element)
+ {
+ if (!queue.offer(element))
+ logger.warn("Queue {} capacity is too small", queue);
+ }
+
+ private static Runnable take(Queue<Runnable> queue)
+ {
+ try
+ {
+ return ((BlockingQueue<Runnable>)queue).take();
+ }
+ catch (InterruptedException x)
+ {
+ throw new RuntimeException(x);
+ }
+ }
+
+ private static Runnable poll(Queue<Runnable> queue)
+ {
+ int loops = 0;
+ while (true)
+ {
+ Runnable element = queue.poll();
+ if (element != null)
+ return element;
+ // Busy loop
+ sleepMicros(1);
+ ++loops;
+ if (loops % 16 == 0)
+ logger.warn("Spin looping while polling empty queue: {} spins: ", loops);
+ }
+ }
+
+ private static void sleepMicros(long sleep)
+ {
+ try
+ {
+ TimeUnit.MICROSECONDS.sleep(sleep);
+ }
+ catch (InterruptedException x)
+ {
+ throw new RuntimeException(x);
+ }
+ }
+
+ private static void await(CyclicBarrier barrier)
+ {
+ try
+ {
+ barrier.await();
+ }
+ catch (Exception x)
+ {
+ throw new RuntimeException(x);
+ }
+ }
+}
diff --git a/pom.xml b/pom.xml
index bf4d128..5b0ccf0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -284,7 +284,7 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
- <argLine>-showversion -XX:+PrintGCDetails</argLine>
+ <argLine>-showversion -Xmx1g -Xms1g -XX:+PrintGCDetails</argLine>
<failIfNoTests>false</failIfNoTests>
<!--systemProperties>
<property>
@@ -702,7 +702,7 @@
})();
</script>
]]>
- </header>
+ </header>
</configuration>
</plugin>
</plugins>
diff --git a/tests/test-webapps/test-jetty-webapp/src/main/config/webapps/test.xml b/tests/test-webapps/test-jetty-webapp/src/main/config/webapps/test.xml
index 1bef8ab..ff7eb6b 100644
--- a/tests/test-webapps/test-jetty-webapp/src/main/config/webapps/test.xml
+++ b/tests/test-webapps/test-jetty-webapp/src/main/config/webapps/test.xml
@@ -45,7 +45,10 @@
<!-- virtual hosts
<Set name="virtualHosts">
<Array type="String">
- <Item>www.myVirtualDomain.com</Item>
+ <Item>www.MyVirtualDomain.com</Item>
+ <Item>m.MyVirtualDomain.com</Item>
+ <Item>*.OtherVirtualDomain.com</Item>
+ <Item>@ConnectorName</Item>
<Item>localhost</Item>
<Item>127.0.0.1</Item>
</Array>