Merge branch 'jetty-9.4.x' into jetty-9.4.x-1555-wwwAuthenticate-Parsing
This commit is contained in:
commit
adb844de64
|
@ -1,6 +1,6 @@
|
|||
#!groovy
|
||||
|
||||
def jdks = ["jdk8", "jdk9","jdk10"]
|
||||
def jdks = ["jdk8","jdk9","jdk10","jdk11"]
|
||||
def oss = ["linux"] //windows? ,"linux-docker"
|
||||
def builds = [:]
|
||||
for (def os in oss) {
|
||||
|
@ -15,7 +15,7 @@ def getFullBuild(jdk, os) {
|
|||
return {
|
||||
node(os) {
|
||||
// System Dependent Locations
|
||||
def mvntool = tool name: 'maven3', type: 'hudson.tasks.Maven$MavenInstallation'
|
||||
def mvntool = tool name: 'maven3.5', type: 'hudson.tasks.Maven$MavenInstallation'
|
||||
def jdktool = tool name: "$jdk", type: 'hudson.model.JDK'
|
||||
|
||||
// Environment
|
||||
|
@ -60,7 +60,7 @@ def getFullBuild(jdk, os) {
|
|||
withEnv(mvnEnv) {
|
||||
timeout(time: 20, unit: 'MINUTES') {
|
||||
withMaven(
|
||||
maven: 'maven3',
|
||||
maven: 'maven3.5',
|
||||
jdk: "$jdk",
|
||||
publisherStrategy: 'EXPLICIT',
|
||||
globalMavenSettingsConfig: 'oss-settings.xml',
|
||||
|
@ -82,7 +82,7 @@ def getFullBuild(jdk, os) {
|
|||
timeout(time: 90, unit: 'MINUTES') {
|
||||
// Run test phase / ignore test failures
|
||||
withMaven(
|
||||
maven: 'maven3',
|
||||
maven: 'maven3.5',
|
||||
jdk: "$jdk",
|
||||
publisherStrategy: 'EXPLICIT',
|
||||
//options: [invokerPublisher(disabled: false)],
|
||||
|
@ -138,7 +138,7 @@ def getFullBuild(jdk, os) {
|
|||
dir("aggregates/jetty-all-compact3") {
|
||||
withEnv(mvnEnv) {
|
||||
withMaven(
|
||||
maven: 'maven3',
|
||||
maven: 'maven3.5',
|
||||
jdk: "$jdk",
|
||||
publisherStrategy: 'EXPLICIT',
|
||||
globalMavenSettingsConfig: 'oss-settings.xml',
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
<Export-Package>org.eclipse.jetty.apache.jsp.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}",
|
||||
org.eclipse.jetty.jsp.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
|
||||
</Export-Package>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
|
||||
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=javax.servlet.ServletContainerInitializer,osgi.serviceloader;osgi.serviceloader=org.apache.juli.logging.Log</Provide-Capability>
|
||||
<_nouses>true</_nouses>
|
||||
</instructions>
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<Import-Package>org.eclipse.jetty.alpn;resolution:=optional,*</Import-Package>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)", osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Client)";cardinality:=multiple</Require-Capability>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional, osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Client)";resolution:=optional;cardinality:=multiple</Require-Capability>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
<Bundle-Description>Conscrypt Client ALPN</Bundle-Description>
|
||||
<Import-Package>org.conscrypt;version="${conscrypt.version}",*</Import-Package>
|
||||
<Export-Package>*</Export-Package>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
|
||||
<Provide-Capability>osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Client</Provide-Capability>
|
||||
<_nouses>true</_nouses>
|
||||
</instructions>
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
<instructions>
|
||||
<Bundle-Description>Conscrypt ALPN</Bundle-Description>
|
||||
<Import-Package>org.conscrypt;version="${conscrypt.version}",*</Import-Package>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
|
||||
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Server</Provide-Capability>
|
||||
<_nouses>true</_nouses>
|
||||
</instructions>
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
<instructions>
|
||||
<Bundle-Description>JDK9 Client ALPN</Bundle-Description>
|
||||
<Export-Package>*</Export-Package>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
|
||||
<Provide-Capability>osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Client</Provide-Capability>
|
||||
<_nouses>true</_nouses>
|
||||
</instructions>
|
||||
|
|
|
@ -33,7 +33,7 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-Description>JDK9 Server ALPN</Bundle-Description>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
|
||||
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Server</Provide-Capability>
|
||||
<_nouses>true</_nouses>
|
||||
</instructions>
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
<Bundle-Description>OpenJDK8 Client ALPN</Bundle-Description>
|
||||
<Import-Package>org.eclipse.jetty.alpn;version="${alpn.majorVersion}.${alpn.minorVersion}.${alpn.incrementalVersion}",*</Import-Package>
|
||||
<Export-Package>*</Export-Package>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
|
||||
<Provide-Capability>osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Client</Provide-Capability>
|
||||
<_nouses>true</_nouses>
|
||||
</instructions>
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
<Bundle-Description>OpenJDK8 Server ALPN</Bundle-Description>
|
||||
<Export-Package>*</Export-Package>
|
||||
<Import-Package>org.eclipse.jetty.alpn;version="${alpn.majorVersion}.${alpn.minorVersion}.${alpn.incrementalVersion}",*</Import-Package>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
|
||||
<Provide-Capability>osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Server</Provide-Capability>
|
||||
<_nouses>true</_nouses>
|
||||
</instructions>
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
<Bundle-SymbolicName>${bundle-symbolic-name};singleton:=true</Bundle-SymbolicName>
|
||||
<Export-Package>org.eclipse.jetty.alpn.server,*</Export-Package>
|
||||
<Import-Package>org.eclipse.jetty.alpn;version="${alpn.majorVersion}.${alpn.minorVersion}.${alpn.incrementalVersion}",*</Import-Package>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)", osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Server)";resolution:=optional;cardinality:=multiple</Require-Capability>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional, osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Server)";resolution:=optional;cardinality:=multiple</Require-Capability>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<Import-Package>org.objectweb.asm;version="[5.0,7)",*</Import-Package>
|
||||
<Require-Capability>osgi.serviceloader; filter:="(osgi.serviceloader=javax.servlet.ServletContainerInitializer)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)"</Require-Capability>
|
||||
<Require-Capability>osgi.serviceloader; filter:="(osgi.serviceloader=javax.servlet.ServletContainerInitializer)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional</Require-Capability>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -47,7 +47,7 @@ public class JettyRunTask extends Task
|
|||
private File tempDirectory;
|
||||
|
||||
/** List of web applications to be deployed. */
|
||||
private List<AntWebAppContext> webapps = new ArrayList<AntWebAppContext>();
|
||||
private List<AntWebAppContext> webapps = new ArrayList<>();
|
||||
|
||||
/** Location of jetty.xml file. */
|
||||
private File jettyXml;
|
||||
|
@ -147,20 +147,17 @@ public class JettyRunTask extends Task
|
|||
{
|
||||
try
|
||||
{
|
||||
this.requestLog = (RequestLog) Class.forName(className).newInstance();
|
||||
}
|
||||
catch (InstantiationException e)
|
||||
{
|
||||
throw new BuildException("Request logger instantiation exception: " + e);
|
||||
}
|
||||
catch (IllegalAccessException e)
|
||||
{
|
||||
throw new BuildException("Request logger instantiation exception: " + e);
|
||||
this.requestLog = (RequestLog) Class.forName(className).getDeclaredConstructor().newInstance();
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
throw new BuildException("Unknown request logger class: " + className);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new BuildException("Request logger instantiation exception: " + e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public String getRequestLog()
|
||||
|
|
|
@ -46,12 +46,12 @@ public abstract class AuthenticationProtocolHandler implements ProtocolHandler
|
|||
{
|
||||
public static final int DEFAULT_MAX_CONTENT_LENGTH = 16*1024;
|
||||
public static final Logger LOG = Log.getLogger(AuthenticationProtocolHandler.class);
|
||||
|
||||
|
||||
private static final Pattern PARAM_PATTERN = Pattern.compile("([^=]+)=([^=]+)?");
|
||||
private static final Pattern TYPE_PATTERN = Pattern.compile("([^\\s]+)(\\s+(.*))?");
|
||||
private static final Pattern MULTIPLE_CHALLENGE_PATTERN = Pattern.compile("(.*),\\s*([^=\\s,]+(\\s+[^=\\s].*)?)\\s*");
|
||||
private static final Pattern BASE64_PATTERN = Pattern.compile("([^\\s,=]+=*)\\s*");
|
||||
|
||||
|
||||
private final HttpClient client;
|
||||
private final int maxContentLength;
|
||||
private final ResponseNotifier notifier;
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-Description>Jetty Http SPI</Bundle-Description>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
|
||||
<Provide-Capability>osgi.serviceloader; osgi.serviceloader=com.sun.net.httpserver.spi.HttpServerProvider</Provide-Capability>
|
||||
<_nouses>true</_nouses>
|
||||
</instructions>
|
||||
|
|
|
@ -55,9 +55,6 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<Require-Capability>osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.http.HttpFieldPreEncoder)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
|
||||
<!--
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
|
||||
-->
|
||||
<Provide-Capability>osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.http.HttpFieldPreEncoder</Provide-Capability>
|
||||
</instructions>
|
||||
</configuration>
|
||||
|
|
|
@ -69,7 +69,6 @@ import org.eclipse.jetty.util.Promise;
|
|||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -314,7 +313,7 @@ public abstract class FlowControlStrategyTest
|
|||
{
|
||||
final int windowSize = 1536;
|
||||
final int length = 5 * windowSize;
|
||||
final CountDownLatch settingsLatch = new CountDownLatch(1);
|
||||
final CountDownLatch settingsLatch = new CountDownLatch(2);
|
||||
start(new ServerSessionListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
|
@ -343,7 +342,9 @@ public abstract class FlowControlStrategyTest
|
|||
|
||||
Map<Integer, Integer> settings = new HashMap<>();
|
||||
settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, windowSize);
|
||||
session.settings(new SettingsFrame(settings, false), Callback.NOOP);
|
||||
Callback.Completable completable = new Callback.Completable();
|
||||
session.settings(new SettingsFrame(settings, false), completable);
|
||||
completable.thenRun(settingsLatch::countDown);
|
||||
|
||||
Assert.assertTrue(settingsLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
|
@ -661,88 +662,6 @@ public abstract class FlowControlStrategyTest
|
|||
Assert.assertArrayEquals(data, bytes);
|
||||
}
|
||||
|
||||
// TODO
|
||||
// Since we changed the API to disallow consecutive data() calls without waiting
|
||||
// for the callback, it is now not possible to have DATA1, DATA2 in the queue for
|
||||
// the same stream. Perhaps this test should just be deleted.
|
||||
@Ignore
|
||||
@Test
|
||||
public void testServerTwoDataFramesWithStalledStream() throws Exception
|
||||
{
|
||||
// Frames in queue = DATA1, DATA2.
|
||||
// Server writes part of DATA1, then stalls.
|
||||
// A window update unstalls the session, verify that the data is correctly sent.
|
||||
|
||||
Random random = new Random();
|
||||
final byte[] chunk1 = new byte[1024];
|
||||
random.nextBytes(chunk1);
|
||||
final byte[] chunk2 = new byte[2048];
|
||||
random.nextBytes(chunk2);
|
||||
|
||||
// Two SETTINGS frames: the initial after the preface,
|
||||
// and the explicit where we set the stream window size to zero.
|
||||
final AtomicReference<CountDownLatch> settingsLatch = new AtomicReference<>(new CountDownLatch(2));
|
||||
final CountDownLatch dataLatch = new CountDownLatch(1);
|
||||
start(new ServerSessionListener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onSettings(Session session, SettingsFrame frame)
|
||||
{
|
||||
settingsLatch.get().countDown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream.Listener onNewStream(Stream stream, HeadersFrame frame)
|
||||
{
|
||||
stream.data(new DataFrame(stream.getId(), ByteBuffer.wrap(chunk1), false), Callback.NOOP);
|
||||
stream.data(new DataFrame(stream.getId(), ByteBuffer.wrap(chunk2), true), Callback.NOOP);
|
||||
dataLatch.countDown();
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
Session session = newClient(new Session.Listener.Adapter());
|
||||
Map<Integer, Integer> settings = new HashMap<>();
|
||||
settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, 0);
|
||||
session.settings(new SettingsFrame(settings, false), Callback.NOOP);
|
||||
Assert.assertTrue(settingsLatch.get().await(5, TimeUnit.SECONDS));
|
||||
|
||||
byte[] content = new byte[chunk1.length + chunk2.length];
|
||||
final ByteBuffer buffer = ByteBuffer.wrap(content);
|
||||
MetaData.Request metaData = newRequest("GET", new HttpFields());
|
||||
HeadersFrame requestFrame = new HeadersFrame(metaData, null, true);
|
||||
final CountDownLatch responseLatch = new CountDownLatch(1);
|
||||
session.newStream(requestFrame, new Promise.Adapter<>(), new Stream.Listener.Adapter()
|
||||
{
|
||||
@Override
|
||||
public void onData(Stream stream, DataFrame frame, Callback callback)
|
||||
{
|
||||
buffer.put(frame.getData());
|
||||
callback.succeeded();
|
||||
if (frame.isEndStream())
|
||||
responseLatch.countDown();
|
||||
}
|
||||
});
|
||||
Assert.assertTrue(dataLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
// Now we have the 2 DATA frames queued in the server.
|
||||
|
||||
// Unstall the stream window.
|
||||
settingsLatch.set(new CountDownLatch(1));
|
||||
settings.clear();
|
||||
settings.put(SettingsFrame.INITIAL_WINDOW_SIZE, chunk1.length / 2);
|
||||
session.settings(new SettingsFrame(settings, false), Callback.NOOP);
|
||||
Assert.assertTrue(settingsLatch.get().await(5, TimeUnit.SECONDS));
|
||||
|
||||
Assert.assertTrue(responseLatch.await(5, TimeUnit.SECONDS));
|
||||
|
||||
// Check that the data is sent correctly.
|
||||
byte[] expected = new byte[content.length];
|
||||
System.arraycopy(chunk1, 0, expected, 0, chunk1.length);
|
||||
System.arraycopy(chunk2, 0, expected, chunk1.length, chunk2.length);
|
||||
Assert.assertArrayEquals(expected, content);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testClientSendingInitialSmallWindow() throws Exception
|
||||
{
|
||||
|
|
|
@ -236,7 +236,7 @@ public class HTTP2Test extends AbstractTest
|
|||
});
|
||||
}
|
||||
|
||||
Assert.assertTrue(latch.await(requests, TimeUnit.SECONDS));
|
||||
Assert.assertTrue(server.dump() + System.lineSeparator() + client.dump(), latch.await(requests, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -103,7 +103,6 @@ public class BufferingFlowControlStrategy extends AbstractFlowControlStrategy
|
|||
|
||||
float ratio = bufferRatio;
|
||||
|
||||
WindowUpdateFrame windowFrame = null;
|
||||
int level = sessionLevel.addAndGet(length);
|
||||
int maxLevel = (int)(maxSessionRecvWindow.get() * ratio);
|
||||
if (level > maxLevel)
|
||||
|
@ -113,7 +112,7 @@ public class BufferingFlowControlStrategy extends AbstractFlowControlStrategy
|
|||
session.updateRecvWindow(level);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Data consumed, {} bytes, updated session recv window by {}/{} for {}", length, level, maxLevel, session);
|
||||
windowFrame = new WindowUpdateFrame(0, level);
|
||||
session.frames(null, Callback.NOOP, new WindowUpdateFrame(0, level), Frame.EMPTY_ARRAY);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -127,7 +126,6 @@ public class BufferingFlowControlStrategy extends AbstractFlowControlStrategy
|
|||
LOG.debug("Data consumed, {} bytes, session recv window level {}/{} for {}", length, level, maxLevel, session);
|
||||
}
|
||||
|
||||
Frame[] windowFrames = Frame.EMPTY_ARRAY;
|
||||
if (stream != null)
|
||||
{
|
||||
if (stream.isRemotelyClosed())
|
||||
|
@ -148,11 +146,7 @@ public class BufferingFlowControlStrategy extends AbstractFlowControlStrategy
|
|||
stream.updateRecvWindow(level);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Data consumed, {} bytes, updated stream recv window by {}/{} for {}", length, level, maxLevel, stream);
|
||||
WindowUpdateFrame frame = new WindowUpdateFrame(stream.getId(), level);
|
||||
if (windowFrame == null)
|
||||
windowFrame = frame;
|
||||
else
|
||||
windowFrames = new Frame[]{frame};
|
||||
session.frames(stream, Callback.NOOP, new WindowUpdateFrame(stream.getId(), level), Frame.EMPTY_ARRAY);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -162,9 +156,6 @@ public class BufferingFlowControlStrategy extends AbstractFlowControlStrategy
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (windowFrame != null)
|
||||
session.frames(stream, Callback.NOOP, windowFrame, windowFrames);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -21,16 +21,17 @@ package org.eclipse.jetty.http2;
|
|||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Deque;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.http2.frames.Frame;
|
||||
import org.eclipse.jetty.http2.frames.WindowUpdateFrame;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.EofException;
|
||||
import org.eclipse.jetty.io.WriteFlusher;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.IteratingCallback;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
|
@ -41,15 +42,16 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
public class HTTP2Flusher extends IteratingCallback implements Dumpable
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(HTTP2Flusher.class);
|
||||
private static final ByteBuffer[] EMPTY_BYTE_BUFFERS = new ByteBuffer[0];
|
||||
|
||||
private final Queue<WindowEntry> windows = new ArrayDeque<>();
|
||||
private final Deque<Entry> frames = new ArrayDeque<>();
|
||||
private final Queue<Entry> entries = new ArrayDeque<>();
|
||||
private final List<Entry> actives = new ArrayList<>();
|
||||
private final Deque<Entry> entries = new ArrayDeque<>();
|
||||
private final Queue<Entry> pendingEntries = new ArrayDeque<>();
|
||||
private final Set<Entry> processedEntries = new HashSet<>();
|
||||
private final HTTP2Session session;
|
||||
private final ByteBufferPool.Lease lease;
|
||||
private Entry stalled;
|
||||
private Throwable terminated;
|
||||
private Entry stalledEntry;
|
||||
|
||||
public HTTP2Flusher(HTTP2Session session)
|
||||
{
|
||||
|
@ -79,9 +81,9 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
|
|||
closed = terminated;
|
||||
if (closed == null)
|
||||
{
|
||||
frames.offerFirst(entry);
|
||||
entries.offerFirst(entry);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Prepended {}, frames={}", entry, frames.size());
|
||||
LOG.debug("Prepended {}, entries={}", entry, entries.size());
|
||||
}
|
||||
}
|
||||
if (closed == null)
|
||||
|
@ -98,9 +100,9 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
|
|||
closed = terminated;
|
||||
if (closed == null)
|
||||
{
|
||||
frames.offer(entry);
|
||||
entries.offer(entry);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Appended {}, frames={}", entry, frames.size());
|
||||
LOG.debug("Appended {}, entries={}", entry, entries.size());
|
||||
}
|
||||
}
|
||||
if (closed == null)
|
||||
|
@ -121,7 +123,7 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
|
|||
{
|
||||
synchronized (this)
|
||||
{
|
||||
return frames.size();
|
||||
return entries.size();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -136,143 +138,158 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
|
|||
if (terminated != null)
|
||||
throw terminated;
|
||||
|
||||
while (!windows.isEmpty())
|
||||
{
|
||||
WindowEntry entry = windows.poll();
|
||||
entry.perform();
|
||||
}
|
||||
WindowEntry windowEntry;
|
||||
while ((windowEntry = windows.poll()) != null)
|
||||
windowEntry.perform();
|
||||
|
||||
for (Entry entry : frames)
|
||||
{
|
||||
entries.offer(entry);
|
||||
actives.add(entry);
|
||||
}
|
||||
frames.clear();
|
||||
Entry entry;
|
||||
while ((entry = entries.poll()) != null)
|
||||
pendingEntries.offer(entry);
|
||||
}
|
||||
|
||||
|
||||
if (entries.isEmpty())
|
||||
if (pendingEntries.isEmpty())
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Flushed {}", session);
|
||||
return Action.IDLE;
|
||||
}
|
||||
|
||||
while (!entries.isEmpty())
|
||||
while (true)
|
||||
{
|
||||
Entry entry = entries.poll();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Processing {}", entry);
|
||||
boolean progress = false;
|
||||
|
||||
// If the stream has been reset or removed, don't send the frame.
|
||||
if (entry.isStale())
|
||||
if (pendingEntries.isEmpty())
|
||||
break;
|
||||
|
||||
Iterator<Entry> pending = pendingEntries.iterator();
|
||||
while (pending.hasNext())
|
||||
{
|
||||
Entry entry = pending.next();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Stale {}", entry);
|
||||
continue;
|
||||
}
|
||||
LOG.debug("Processing {}", entry);
|
||||
|
||||
try
|
||||
{
|
||||
if (entry.generate(lease))
|
||||
// If the stream has been reset or removed,
|
||||
// don't send the frame and fail it here.
|
||||
if (entry.isStale())
|
||||
{
|
||||
if (entry.getDataBytesRemaining() > 0)
|
||||
entries.offer(entry);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Stale {}", entry);
|
||||
entry.failed(new EofException("reset"));
|
||||
pending.remove();
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
||||
try
|
||||
{
|
||||
if (stalled == null)
|
||||
stalled = entry;
|
||||
if (entry.generate(lease))
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Generated {} frame bytes for {}", entry.getFrameBytesGenerated(), entry);
|
||||
|
||||
progress = true;
|
||||
|
||||
processedEntries.add(entry);
|
||||
|
||||
if (entry.getDataBytesRemaining() == 0)
|
||||
pending.remove();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (session.getSendWindow() <= 0 && stalledEntry == null)
|
||||
{
|
||||
stalledEntry = entry;
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Flow control stalled at {}", entry);
|
||||
// Continue to process control frames.
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable failure)
|
||||
{
|
||||
// Failure to generate the entry is catastrophic.
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Failure generating " + entry, failure);
|
||||
failed(failure);
|
||||
return Action.SUCCEEDED;
|
||||
}
|
||||
}
|
||||
catch (Throwable failure)
|
||||
|
||||
if (!progress)
|
||||
break;
|
||||
|
||||
if (stalledEntry != null)
|
||||
break;
|
||||
|
||||
int writeThreshold = session.getWriteThreshold();
|
||||
if (lease.getTotalLength() >= writeThreshold)
|
||||
{
|
||||
// Failure to generate the entry is catastrophic.
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Failure generating frame " + entry.frame, failure);
|
||||
failed(failure);
|
||||
return Action.SUCCEEDED;
|
||||
LOG.debug("Write threshold {} exceeded", writeThreshold);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
List<ByteBuffer> byteBuffers = lease.getByteBuffers();
|
||||
if (byteBuffers.isEmpty())
|
||||
{
|
||||
complete();
|
||||
finish();
|
||||
return Action.IDLE;
|
||||
}
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Writing {} buffers ({} bytes) for {} frames {}", byteBuffers.size(), lease.getTotalLength(), actives.size(), actives);
|
||||
session.getEndPoint().write(this, byteBuffers.toArray(new ByteBuffer[byteBuffers.size()]));
|
||||
LOG.debug("Writing {} buffers ({} bytes) - entries processed/pending {}/{}: {}/{}",
|
||||
byteBuffers.size(),
|
||||
lease.getTotalLength(),
|
||||
processedEntries.size(),
|
||||
pendingEntries.size(),
|
||||
processedEntries,
|
||||
pendingEntries);
|
||||
|
||||
session.getEndPoint().write(this, byteBuffers.toArray(EMPTY_BYTE_BUFFERS));
|
||||
return Action.SCHEDULED;
|
||||
}
|
||||
|
||||
void onFlushed(long bytes) throws IOException
|
||||
{
|
||||
// For the given flushed bytes, we want to only
|
||||
// forward those that belong to data frame content.
|
||||
for (Entry entry : actives)
|
||||
{
|
||||
int frameBytesLeft = entry.getFrameBytesRemaining();
|
||||
if (frameBytesLeft > 0)
|
||||
{
|
||||
int update = (int)Math.min(bytes, frameBytesLeft);
|
||||
entry.onFrameBytesFlushed(update);
|
||||
bytes -= update;
|
||||
IStream stream = entry.stream;
|
||||
if (stream != null && !entry.isControl())
|
||||
{
|
||||
Object channel = stream.getAttachment();
|
||||
if (channel instanceof WriteFlusher.Listener)
|
||||
((WriteFlusher.Listener)channel).onFlushed(update - Frame.HEADER_LENGTH);
|
||||
}
|
||||
if (bytes == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
// A single EndPoint write may be flushed multiple times (for example with SSL).
|
||||
for (Entry entry : processedEntries)
|
||||
bytes = entry.onFlushed(bytes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Written {} frames for {}", actives.size(), actives);
|
||||
|
||||
complete();
|
||||
|
||||
LOG.debug("Written {} buffers - entries processed/pending {}/{}: {}/{}",
|
||||
lease.getByteBuffers().size(),
|
||||
processedEntries.size(),
|
||||
pendingEntries.size(),
|
||||
processedEntries,
|
||||
pendingEntries);
|
||||
finish();
|
||||
super.succeeded();
|
||||
}
|
||||
|
||||
private void complete()
|
||||
private void finish()
|
||||
{
|
||||
lease.recycle();
|
||||
|
||||
actives.forEach(Entry::complete);
|
||||
processedEntries.forEach(Entry::succeeded);
|
||||
processedEntries.clear();
|
||||
|
||||
if (stalled != null)
|
||||
if (stalledEntry != null)
|
||||
{
|
||||
// We have written part of the frame, but there is more to write.
|
||||
// The API will not allow to send two data frames for the same
|
||||
// stream so we append the unfinished frame at the end to allow
|
||||
// better interleaving with other streams.
|
||||
int index = actives.indexOf(stalled);
|
||||
for (int i = index; i < actives.size(); ++i)
|
||||
int size = pendingEntries.size();
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
Entry entry = actives.get(i);
|
||||
if (entry.getDataBytesRemaining() > 0)
|
||||
append(entry);
|
||||
Entry entry = pendingEntries.peek();
|
||||
if (entry == stalledEntry)
|
||||
break;
|
||||
pendingEntries.poll();
|
||||
pendingEntries.offer(entry);
|
||||
}
|
||||
for (int i = 0; i < index; ++i)
|
||||
{
|
||||
Entry entry = actives.get(i);
|
||||
if (entry.getDataBytesRemaining() > 0)
|
||||
append(entry);
|
||||
}
|
||||
stalled = null;
|
||||
stalledEntry = null;
|
||||
}
|
||||
|
||||
actives.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -287,18 +304,26 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
|
|||
lease.recycle();
|
||||
|
||||
Throwable closed;
|
||||
Set<Entry> allEntries;
|
||||
synchronized (this)
|
||||
{
|
||||
closed = terminated;
|
||||
terminated = x;
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{}, active/queued={}/{}", closed != null ? "Closing" : "Failing", actives.size(), frames.size());
|
||||
actives.addAll(frames);
|
||||
frames.clear();
|
||||
LOG.debug(String.format("%s, entries processed/pending/queued=%d/%d/%d",
|
||||
closed != null ? "Closing" : "Failing",
|
||||
processedEntries.size(),
|
||||
pendingEntries.size(),
|
||||
entries.size()), x);
|
||||
allEntries = new HashSet<>(entries);
|
||||
entries.clear();
|
||||
}
|
||||
|
||||
actives.forEach(entry -> entry.failed(x));
|
||||
actives.clear();
|
||||
allEntries.addAll(processedEntries);
|
||||
processedEntries.clear();
|
||||
allEntries.addAll(pendingEntries);
|
||||
pendingEntries.clear();
|
||||
allEntries.forEach(entry -> entry.failed(x));
|
||||
|
||||
// If the failure came from within the
|
||||
// flusher, we need to close the connection.
|
||||
|
@ -340,11 +365,12 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
|
|||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s[window_queue=%d,frame_queue=%d,actives=%d]",
|
||||
return String.format("%s[window_queue=%d,frame_queue=%d,processed/pending=%d/%d]",
|
||||
super.toString(),
|
||||
getWindowQueueSize(),
|
||||
getFrameQueueSize(),
|
||||
actives.size());
|
||||
processedEntries.size(),
|
||||
pendingEntries.size());
|
||||
}
|
||||
|
||||
public static abstract class Entry extends Callback.Nested
|
||||
|
@ -359,9 +385,7 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
|
|||
this.stream = stream;
|
||||
}
|
||||
|
||||
public abstract int getFrameBytesRemaining();
|
||||
|
||||
public abstract void onFrameBytesFlushed(int bytesFlushed);
|
||||
public abstract int getFrameBytesGenerated();
|
||||
|
||||
public int getDataBytesRemaining()
|
||||
{
|
||||
|
@ -370,13 +394,7 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
|
|||
|
||||
protected abstract boolean generate(ByteBufferPool.Lease lease);
|
||||
|
||||
private void complete()
|
||||
{
|
||||
if (isStale())
|
||||
failed(new EofException("reset"));
|
||||
else
|
||||
succeeded();
|
||||
}
|
||||
public abstract long onFlushed(long bytes) throws IOException;
|
||||
|
||||
@Override
|
||||
public void failed(Throwable x)
|
||||
|
@ -417,17 +435,6 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable
|
|||
}
|
||||
}
|
||||
|
||||
private boolean isControl()
|
||||
{
|
||||
switch (frame.getType())
|
||||
{
|
||||
case DATA:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
|
|
@ -51,6 +51,7 @@ import org.eclipse.jetty.http2.generator.Generator;
|
|||
import org.eclipse.jetty.http2.parser.Parser;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.io.WriteFlusher;
|
||||
import org.eclipse.jetty.util.AtomicBiInteger;
|
||||
import org.eclipse.jetty.util.Atomics;
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
|
@ -88,6 +89,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
private int maxRemoteStreams;
|
||||
private long streamIdleTimeout;
|
||||
private int initialSessionRecvWindow;
|
||||
private int writeThreshold;
|
||||
private boolean pushEnabled;
|
||||
private long idleTime;
|
||||
private GoAwayFrame closeFrame;
|
||||
|
@ -106,6 +108,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
this.streamIdleTimeout = endPoint.getIdleTimeout();
|
||||
this.sendWindow.set(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
|
||||
this.recvWindow.set(FlowControlStrategy.DEFAULT_WINDOW_SIZE);
|
||||
this.writeThreshold = 32 * 1024;
|
||||
this.pushEnabled = true; // SPEC: by default, push is enabled.
|
||||
this.idleTime = System.nanoTime();
|
||||
addBean(flowControl);
|
||||
|
@ -186,6 +189,16 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
this.initialSessionRecvWindow = initialSessionRecvWindow;
|
||||
}
|
||||
|
||||
public int getWriteThreshold()
|
||||
{
|
||||
return writeThreshold;
|
||||
}
|
||||
|
||||
public void setWriteThreshold(int writeThreshold)
|
||||
{
|
||||
this.writeThreshold = writeThreshold;
|
||||
}
|
||||
|
||||
public EndPoint getEndPoint()
|
||||
{
|
||||
return endPoint;
|
||||
|
@ -1144,7 +1157,6 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
|
||||
private class ControlEntry extends HTTP2Flusher.Entry
|
||||
{
|
||||
private int bytes;
|
||||
private int frameBytes;
|
||||
|
||||
private ControlEntry(Frame frame, IStream stream, Callback callback)
|
||||
|
@ -1153,25 +1165,27 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
}
|
||||
|
||||
@Override
|
||||
public int getFrameBytesRemaining()
|
||||
public int getFrameBytesGenerated()
|
||||
{
|
||||
return frameBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFrameBytesFlushed(int bytesFlushed)
|
||||
protected boolean generate(ByteBufferPool.Lease lease)
|
||||
{
|
||||
frameBytes -= bytesFlushed;
|
||||
frameBytes = generator.control(lease, frame);
|
||||
beforeSend();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean generate(ByteBufferPool.Lease lease)
|
||||
public long onFlushed(long bytes)
|
||||
{
|
||||
bytes = frameBytes = generator.control(lease, frame);
|
||||
long flushed = Math.min(frameBytes, bytes);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Generated {}", frame);
|
||||
beforeSend();
|
||||
return true;
|
||||
LOG.debug("Flushed {}/{} frame bytes for {}", flushed, bytes, this);
|
||||
frameBytes -= flushed;
|
||||
return bytes - flushed;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1215,7 +1229,9 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
bytesWritten.addAndGet(bytes);
|
||||
bytesWritten.addAndGet(frameBytes);
|
||||
frameBytes = 0;
|
||||
|
||||
switch (frame.getType())
|
||||
{
|
||||
case HEADERS:
|
||||
|
@ -1264,6 +1280,7 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
super.succeeded();
|
||||
}
|
||||
|
||||
|
@ -1278,10 +1295,10 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
|
||||
private class DataEntry extends HTTP2Flusher.Entry
|
||||
{
|
||||
private int bytes;
|
||||
private int frameBytes;
|
||||
private int frameRemaining;
|
||||
private int dataBytes;
|
||||
private int dataWritten;
|
||||
private int dataRemaining;
|
||||
|
||||
private DataEntry(DataFrame frame, IStream stream, Callback callback)
|
||||
{
|
||||
|
@ -1291,61 +1308,74 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements ISessio
|
|||
// of data frames that cannot be completely written due to
|
||||
// the flow control window exhausting, since in that case
|
||||
// we would have to count the padding only once.
|
||||
dataBytes = frame.remaining();
|
||||
dataRemaining = frame.remaining();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFrameBytesRemaining()
|
||||
public int getFrameBytesGenerated()
|
||||
{
|
||||
return frameBytes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFrameBytesFlushed(int bytesFlushed)
|
||||
{
|
||||
frameBytes -= bytesFlushed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDataBytesRemaining()
|
||||
{
|
||||
return dataBytes;
|
||||
return dataRemaining;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean generate(ByteBufferPool.Lease lease)
|
||||
{
|
||||
int dataBytes = getDataBytesRemaining();
|
||||
int dataRemaining = getDataBytesRemaining();
|
||||
|
||||
int sessionSendWindow = getSendWindow();
|
||||
int streamSendWindow = stream.updateSendWindow(0);
|
||||
int window = Math.min(streamSendWindow, sessionSendWindow);
|
||||
if (window <= 0 && dataBytes > 0)
|
||||
if (window <= 0 && dataRemaining > 0)
|
||||
return false;
|
||||
|
||||
int length = Math.min(dataBytes, window);
|
||||
int length = Math.min(dataRemaining, window);
|
||||
|
||||
// Only one DATA frame is generated.
|
||||
DataFrame dataFrame = (DataFrame)frame;
|
||||
bytes = frameBytes = generator.data(lease, dataFrame, length);
|
||||
int written = bytes - Frame.HEADER_LENGTH;
|
||||
int frameBytes = generator.data(lease, (DataFrame)frame, length);
|
||||
this.frameBytes += frameBytes;
|
||||
this.frameRemaining += frameBytes;
|
||||
|
||||
int dataBytes = frameBytes - Frame.HEADER_LENGTH;
|
||||
this.dataBytes += dataBytes;
|
||||
this.dataRemaining -= dataBytes;
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Generated {}, length/window/data={}/{}/{}", dataFrame, written, window, dataBytes);
|
||||
LOG.debug("Generated {}, length/window/data={}/{}/{}", frame, dataBytes, window, dataRemaining);
|
||||
|
||||
this.dataWritten = written;
|
||||
this.dataBytes -= written;
|
||||
|
||||
flowControl.onDataSending(stream, written);
|
||||
stream.updateClose(dataFrame.isEndStream(), CloseState.Event.BEFORE_SEND);
|
||||
flowControl.onDataSending(stream, dataBytes);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long onFlushed(long bytes) throws IOException
|
||||
{
|
||||
long flushed = Math.min(frameRemaining, bytes);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Flushed {}/{} frame bytes for {}", flushed, bytes, this);
|
||||
frameRemaining -= flushed;
|
||||
// We should only forward data (not frame) bytes,
|
||||
// but we trade precision for simplicity.
|
||||
Object channel = stream.getAttachment();
|
||||
if (channel instanceof WriteFlusher.Listener)
|
||||
((WriteFlusher.Listener)channel).onFlushed(flushed);
|
||||
return bytes - flushed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
bytesWritten.addAndGet(bytes);
|
||||
flowControl.onDataSent(stream, dataWritten);
|
||||
bytesWritten.addAndGet(frameBytes);
|
||||
frameBytes = 0;
|
||||
frameRemaining = 0;
|
||||
|
||||
flowControl.onDataSent(stream, dataBytes);
|
||||
dataBytes = 0;
|
||||
|
||||
// Do we have more to send ?
|
||||
DataFrame dataFrame = (DataFrame)frame;
|
||||
|
|
|
@ -51,7 +51,7 @@
|
|||
<configuration>
|
||||
<instructions>
|
||||
<Bundle-Description>Http2 Hpack</Bundle-Description>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
|
||||
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.http.HttpFieldPreEncoder</Provide-Capability>
|
||||
<_nouses>true</_nouses>
|
||||
</instructions>
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.eclipse.jetty.http2.BufferingFlowControlStrategy;
|
|||
import org.eclipse.jetty.http2.FlowControlStrategy;
|
||||
import org.eclipse.jetty.http2.HTTP2Connection;
|
||||
import org.eclipse.jetty.http2.api.server.ServerSessionListener;
|
||||
import org.eclipse.jetty.http2.frames.Frame;
|
||||
import org.eclipse.jetty.http2.generator.Generator;
|
||||
import org.eclipse.jetty.http2.parser.ServerParser;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
|
@ -62,6 +63,7 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
|
|||
throw new IllegalArgumentException("Unsupported HTTP2 Protocol variant: "+p);
|
||||
this.httpConfiguration = Objects.requireNonNull(httpConfiguration);
|
||||
addBean(httpConfiguration);
|
||||
setInputBufferSize(Frame.DEFAULT_MAX_LENGTH + Frame.HEADER_LENGTH);
|
||||
}
|
||||
|
||||
@ManagedAttribute("The HPACK dynamic table maximum size")
|
||||
|
@ -185,7 +187,8 @@ public abstract class AbstractHTTP2ServerConnectionFactory extends AbstractConne
|
|||
streamIdleTimeout = endPoint.getIdleTimeout();
|
||||
session.setStreamIdleTimeout(streamIdleTimeout);
|
||||
session.setInitialSessionRecvWindow(getInitialSessionRecvWindow());
|
||||
|
||||
session.setWriteThreshold(getHttpConfiguration().getOutputBufferSize());
|
||||
|
||||
ServerParser parser = newServerParser(connector, session);
|
||||
HTTP2Connection connection = new HTTP2ServerConnection(connector.getByteBufferPool(), connector.getExecutor(),
|
||||
endPoint, httpConfiguration, parser, session, getInputBufferSize(), listener);
|
||||
|
|
|
@ -101,8 +101,8 @@ public interface ByteBufferPool
|
|||
public long getTotalLength()
|
||||
{
|
||||
long length = 0;
|
||||
for (int i = 0; i < buffers.size(); ++i)
|
||||
length += buffers.get(i).remaining();
|
||||
for (ByteBuffer buffer : buffers)
|
||||
length += buffer.remaining();
|
||||
return length;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,5 +34,10 @@
|
|||
<artifactId>jetty-security</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
|
|
@ -20,7 +20,6 @@ package org.eclipse.jetty.jaas;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.security.Principal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashSet;
|
||||
|
@ -42,15 +41,20 @@ import org.eclipse.jetty.security.DefaultIdentityService;
|
|||
import org.eclipse.jetty.security.IdentityService;
|
||||
import org.eclipse.jetty.security.LoginService;
|
||||
import org.eclipse.jetty.server.UserIdentity;
|
||||
import org.eclipse.jetty.util.ArrayUtil;
|
||||
import org.eclipse.jetty.util.Loader;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
/* ---------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* JAASLoginService
|
||||
*
|
||||
*
|
||||
* Implementation of jetty's LoginService that works with JAAS for
|
||||
* authorization and authentication.
|
||||
*
|
||||
*/
|
||||
public class JAASLoginService extends AbstractLifeCycle implements LoginService
|
||||
{
|
||||
|
@ -66,9 +70,8 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
|
|||
protected JAASUserPrincipal _defaultUser = new JAASUserPrincipal(null, null, null);
|
||||
protected IdentityService _identityService;
|
||||
|
||||
/* ---------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
*/
|
||||
public JAASLoginService()
|
||||
|
@ -76,9 +79,8 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
|
|||
}
|
||||
|
||||
|
||||
/* ---------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param name the name of the realm
|
||||
*/
|
||||
|
@ -90,7 +92,7 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
|
|||
}
|
||||
|
||||
|
||||
/* ---------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Get the name of the realm.
|
||||
*
|
||||
|
@ -103,7 +105,7 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
|
|||
}
|
||||
|
||||
|
||||
/* ---------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Set the name of the realm
|
||||
*
|
||||
|
@ -114,7 +116,7 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
|
|||
_realmName = name;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/** Get the identityService.
|
||||
* @return the identityService
|
||||
*/
|
||||
|
@ -124,7 +126,7 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
|
|||
return _identityService;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/** Set the identityService.
|
||||
* @param identityService the identityService to set
|
||||
*/
|
||||
|
@ -134,7 +136,7 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
|
|||
_identityService = identityService;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* Set the name to use to index into the config
|
||||
* file of LoginModules.
|
||||
|
@ -146,44 +148,41 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
|
|||
_loginModuleName = name;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
public void setCallbackHandlerClass (String classname)
|
||||
{
|
||||
_callbackHandlerClass = classname;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
public void setRoleClassNames (String[] classnames)
|
||||
{
|
||||
ArrayList<String> tmp = new ArrayList<String>();
|
||||
|
||||
if (classnames != null)
|
||||
tmp.addAll(Arrays.asList(classnames));
|
||||
|
||||
if (!tmp.contains(DEFAULT_ROLE_CLASS_NAME))
|
||||
tmp.add(DEFAULT_ROLE_CLASS_NAME);
|
||||
_roleClassNames = tmp.toArray(new String[tmp.size()]);
|
||||
if (classnames == null || classnames.length == 0)
|
||||
{
|
||||
_roleClassNames = DEFAULT_ROLE_CLASS_NAMES;
|
||||
return;
|
||||
}
|
||||
|
||||
_roleClassNames = ArrayUtil.addToArray(classnames, DEFAULT_ROLE_CLASS_NAME, String.class);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
public String[] getRoleClassNames()
|
||||
{
|
||||
return _roleClassNames;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
|
||||
*/
|
||||
|
||||
|
||||
@Override
|
||||
protected void doStart() throws Exception
|
||||
{
|
||||
if (_identityService==null)
|
||||
_identityService=new DefaultIdentityService();
|
||||
_identityService = new DefaultIdentityService();
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
@Override
|
||||
public UserIdentity login(final String username,final Object credentials, final ServletRequest request)
|
||||
{
|
||||
|
@ -207,7 +206,7 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
|
|||
}
|
||||
else if (callback instanceof PasswordCallback)
|
||||
{
|
||||
((PasswordCallback)callback).setPassword((char[]) credentials.toString().toCharArray());
|
||||
((PasswordCallback)callback).setPassword(credentials.toString().toCharArray());
|
||||
}
|
||||
else if (callback instanceof ObjectCallback)
|
||||
{
|
||||
|
@ -228,7 +227,7 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
|
|||
else
|
||||
{
|
||||
Class<?> clazz = Loader.loadClass(_callbackHandlerClass);
|
||||
callbackHandler = (CallbackHandler)clazz.newInstance();
|
||||
callbackHandler = (CallbackHandler)clazz.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
//set up the login context
|
||||
//TODO jaspi requires we provide the Configuration parameter
|
||||
|
@ -243,34 +242,14 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
|
|||
|
||||
return _identityService.newUserIdentity(subject,userPrincipal,getGroups(subject));
|
||||
}
|
||||
catch (LoginException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
catch (UnsupportedCallbackException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
catch (InstantiationException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
catch (IllegalAccessException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
@Override
|
||||
public boolean validate(UserIdentity user)
|
||||
{
|
||||
|
@ -278,7 +257,7 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
|
|||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
private String getUserName(CallbackHandler callbackHandler) throws IOException, UnsupportedCallbackException
|
||||
{
|
||||
NameCallback nameCallback = new NameCallback("foo");
|
||||
|
@ -286,7 +265,7 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
|
|||
return nameCallback.getName();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
@Override
|
||||
public void logout(UserIdentity user)
|
||||
{
|
||||
|
@ -303,31 +282,64 @@ public class JAASLoginService extends AbstractLifeCycle implements LoginService
|
|||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private String[] getGroups (Subject subject)
|
||||
/**
|
||||
* Get all of the groups for the user.
|
||||
*
|
||||
* @param subject the Subject representing the user
|
||||
*
|
||||
* @return all the names of groups that the user is in, or 0 length array if none
|
||||
*/
|
||||
protected String[] getGroups (Subject subject)
|
||||
{
|
||||
//get all the roles of the various types
|
||||
String[] roleClassNames = getRoleClassNames();
|
||||
Collection<String> groups = new LinkedHashSet<String>();
|
||||
try
|
||||
Collection<String> groups = new LinkedHashSet<>();
|
||||
Set<Principal> principals = subject.getPrincipals();
|
||||
for (Principal principal : principals)
|
||||
{
|
||||
for (String roleClassName : roleClassNames)
|
||||
Class<?> c = principal.getClass();
|
||||
while (c!=null)
|
||||
{
|
||||
Class load_class = Thread.currentThread().getContextClassLoader().loadClass(roleClassName);
|
||||
Set<Principal> rolesForType = subject.getPrincipals(load_class);
|
||||
for (Principal principal : rolesForType)
|
||||
if (roleClassNameMatches(c.getName()))
|
||||
{
|
||||
groups.add(principal.getName());
|
||||
break;
|
||||
}
|
||||
|
||||
boolean added = false;
|
||||
for (Class<?> ci:c.getInterfaces())
|
||||
{
|
||||
if (roleClassNameMatches(ci.getName()))
|
||||
{
|
||||
groups.add(principal.getName());
|
||||
added = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!added)
|
||||
{
|
||||
c = c.getSuperclass();
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return groups.toArray(new String[groups.size()]);
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
return groups.toArray(new String[groups.size()]);
|
||||
}
|
||||
|
||||
|
||||
private boolean roleClassNameMatches (String classname)
|
||||
{
|
||||
boolean result = false;
|
||||
for (String roleClassName:getRoleClassNames())
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
if (roleClassName.equals(classname))
|
||||
{
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -105,17 +105,9 @@ public class JDBCLoginModule extends AbstractDatabaseLoginModule
|
|||
dbPassword = "";
|
||||
|
||||
if (dbDriver != null)
|
||||
Loader.loadClass(dbDriver).newInstance();
|
||||
Loader.loadClass(dbDriver).getDeclaredConstructor().newInstance();
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
throw new IllegalStateException (e.toString());
|
||||
}
|
||||
catch (InstantiationException e)
|
||||
{
|
||||
throw new IllegalStateException (e.toString());
|
||||
}
|
||||
catch (IllegalAccessException e)
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IllegalStateException (e.toString());
|
||||
}
|
||||
|
|
|
@ -0,0 +1,146 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2018 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.jaas;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.security.Principal;
|
||||
|
||||
import javax.security.auth.Subject;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* JAASLoginServiceTest
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class JAASLoginServiceTest
|
||||
{
|
||||
interface SomeRole
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public class TestRole implements Principal, SomeRole
|
||||
{
|
||||
String _name;
|
||||
|
||||
public TestRole (String name)
|
||||
{
|
||||
_name = name;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class AnotherTestRole extends TestRole
|
||||
{
|
||||
public AnotherTestRole(String name)
|
||||
{
|
||||
super(name);
|
||||
}
|
||||
}
|
||||
|
||||
public class NotTestRole implements Principal
|
||||
{
|
||||
String _name;
|
||||
|
||||
public NotTestRole (String n)
|
||||
{
|
||||
_name = n;
|
||||
}
|
||||
|
||||
public String getName()
|
||||
{
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testLoginServiceRoles () throws Exception
|
||||
{
|
||||
JAASLoginService ls = new JAASLoginService("foo");
|
||||
|
||||
//test that we always add in the DEFAULT ROLE CLASSNAME
|
||||
ls.setRoleClassNames(new String[] {"arole", "brole"});
|
||||
String[] roles = ls.getRoleClassNames();
|
||||
assertEquals(3, roles.length);
|
||||
assertEquals(JAASLoginService.DEFAULT_ROLE_CLASS_NAME, roles[2]);
|
||||
|
||||
ls.setRoleClassNames(new String[] {});
|
||||
assertEquals(1, ls.getRoleClassNames().length);
|
||||
assertEquals(JAASLoginService.DEFAULT_ROLE_CLASS_NAME, ls.getRoleClassNames()[0]);
|
||||
|
||||
ls.setRoleClassNames(null);
|
||||
assertEquals(1, ls.getRoleClassNames().length);
|
||||
assertEquals(JAASLoginService.DEFAULT_ROLE_CLASS_NAME, ls.getRoleClassNames()[0]);
|
||||
|
||||
//test a custom role class where some of the roles are subclasses of it
|
||||
ls.setRoleClassNames(new String[] {TestRole.class.getName()});
|
||||
Subject subject = new Subject();
|
||||
subject.getPrincipals().add(new NotTestRole("w"));
|
||||
subject.getPrincipals().add(new TestRole("x"));
|
||||
subject.getPrincipals().add(new TestRole("y"));
|
||||
subject.getPrincipals().add(new AnotherTestRole("z"));
|
||||
|
||||
String[] groups = ls.getGroups(subject);
|
||||
assertEquals(3, groups.length);
|
||||
for (String g:groups)
|
||||
assertTrue(g.equals("x") || g.equals("y") || g.equals("z"));
|
||||
|
||||
//test a custom role class
|
||||
ls.setRoleClassNames(new String[] {AnotherTestRole.class.getName()});
|
||||
Subject subject2 = new Subject();
|
||||
subject2.getPrincipals().add(new NotTestRole("w"));
|
||||
subject2.getPrincipals().add(new TestRole("x"));
|
||||
subject2.getPrincipals().add(new TestRole("y"));
|
||||
subject2.getPrincipals().add(new AnotherTestRole("z"));
|
||||
assertEquals(1, ls.getGroups(subject2).length);
|
||||
assertEquals("z", ls.getGroups(subject2)[0]);
|
||||
|
||||
//test a custom role class that implements an interface
|
||||
ls.setRoleClassNames(new String[] {SomeRole.class.getName()});
|
||||
Subject subject3 = new Subject();
|
||||
subject3.getPrincipals().add(new NotTestRole("w"));
|
||||
subject3.getPrincipals().add(new TestRole("x"));
|
||||
subject3.getPrincipals().add(new TestRole("y"));
|
||||
subject3.getPrincipals().add(new AnotherTestRole("z"));
|
||||
assertEquals(3, ls.getGroups(subject3).length);
|
||||
for (String g:groups)
|
||||
assertTrue(g.equals("x") || g.equals("y") || g.equals("z"));
|
||||
|
||||
//test a class that doesn't match
|
||||
ls.setRoleClassNames(new String[] {NotTestRole.class.getName()});
|
||||
Subject subject4 = new Subject();
|
||||
subject4.getPrincipals().add(new TestRole("x"));
|
||||
subject4.getPrincipals().add(new TestRole("y"));
|
||||
subject4.getPrincipals().add(new AnotherTestRole("z"));
|
||||
assertEquals(0, ls.getGroups(subject4).length);
|
||||
}
|
||||
|
||||
}
|
|
@ -148,7 +148,7 @@ public class ObjectMBean implements DynamicMBean
|
|||
LOG.ignore(e);
|
||||
if (ModelMBean.class.isAssignableFrom(mClass))
|
||||
{
|
||||
mbean = mClass.newInstance();
|
||||
mbean = mClass.getDeclaredConstructor().newInstance();
|
||||
((ModelMBean)mbean).setManagedResource(o, "objectReference");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -187,7 +187,9 @@ public class ContextFactory implements ObjectFactory
|
|||
Reference ref = (Reference)obj;
|
||||
StringRefAddr parserAddr = (StringRefAddr)ref.get("parser");
|
||||
String parserClassName = (parserAddr==null?null:(String)parserAddr.getContent());
|
||||
NameParser parser = (NameParser)(parserClassName==null?null:loader.loadClass(parserClassName).newInstance());
|
||||
NameParser parser =
|
||||
(NameParser)(parserClassName==null?
|
||||
null:loader.loadClass(parserClassName).getDeclaredConstructor().newInstance());
|
||||
|
||||
return new NamingContext (env,
|
||||
name.get(0),
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
invoker.goals = test -fae
|
|
@ -0,0 +1,106 @@
|
|||
<?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">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.eclipse.jetty.its.jetty-cdi-run-forked-mojo-it</groupId>
|
||||
<artifactId>jetty-weld-minimal</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>war</packaging>
|
||||
|
||||
<properties>
|
||||
<jetty.version>@project.version@</jetty.version>
|
||||
<weld.version>2.4.5.Final</weld.version>
|
||||
<jetty.port.file>${project.build.directory}/jetty-cdi-run-forked-port.txt</jetty.port.file>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jboss.weld.servlet</groupId>
|
||||
<artifactId>weld-servlet</artifactId>
|
||||
<version>${weld.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<version>3.1.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-client</artifactId>
|
||||
<version>@project.version@</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.5.1</version>
|
||||
<configuration>
|
||||
<target>1.8</target>
|
||||
<source>1.8</source>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>@surefireVersion@</version>
|
||||
<configuration>
|
||||
<systemPropertyVariables>
|
||||
<jetty.port.file>${jetty.port.file}</jetty.port.file>
|
||||
</systemPropertyVariables>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-maven-plugin</artifactId>
|
||||
<version>@project.version@</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>start-jetty</id>
|
||||
<phase>test-compile</phase>
|
||||
<goals>
|
||||
<goal>run-forked</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<nonBlocking>true</nonBlocking>
|
||||
<waitForChild>false</waitForChild>
|
||||
|
||||
<!-- Set up configuration for Weld. -->
|
||||
<contextXml>${basedir}/src/main/jetty/jetty-context.xml</contextXml>
|
||||
<jettyXml>${basedir}/src/main/jetty/jetty.xml</jettyXml>
|
||||
<stopPort>@jetty.stopPort@</stopPort>
|
||||
<stopKey>@jetty.stopKey@</stopKey>
|
||||
|
||||
<jvmArgs>${jetty.jvmArgs}</jvmArgs>
|
||||
<jettyProperties>
|
||||
<jettyProperty>jetty.port.file=${jetty.port.file}</jettyProperty>
|
||||
</jettyProperties>
|
||||
</configuration>
|
||||
</execution>
|
||||
<!--
|
||||
<execution>
|
||||
<id>stop-jetty</id>
|
||||
<phase>test</phase>
|
||||
<goals>
|
||||
<goal>stop</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
-->
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,13 @@
|
|||
|
||||
|
||||
System.out.println( "running postbuild.groovy port " + jettyStopPort + ", key:" + jettyStopKey )
|
||||
|
||||
int port = Integer.parseInt( jettyStopPort )
|
||||
|
||||
Socket s=new Socket(InetAddress.getByName("127.0.0.1"),port )
|
||||
s.setSoLinger(false, 0)
|
||||
|
||||
OutputStream out=s.getOutputStream()
|
||||
out.write(( jettyStopKey +"\r\nforcestop\r\n").getBytes())
|
||||
out.flush()
|
||||
s.close()
|
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2018 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 test;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.annotation.WebServlet;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
@WebServlet( "/*" )
|
||||
public class Greeter
|
||||
extends HttpServlet
|
||||
{
|
||||
|
||||
@Override
|
||||
protected void doGet( final HttpServletRequest req, final HttpServletResponse resp )
|
||||
throws ServletException, IOException
|
||||
{
|
||||
resp.getWriter().print( "Hello" );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="ISO-8859-1"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<!-- Weld needs access to some internal classes. Same configuration as "cdi2" module provides on server. -->
|
||||
|
||||
<Configure class="org.eclipse.jetty.webapp.WebAppContext">
|
||||
|
||||
<Call name="prependServerClass">
|
||||
<Arg>-org.eclipse.jetty.util.Decorator</Arg>
|
||||
</Call>
|
||||
<Call name="prependServerClass">
|
||||
<Arg>-org.eclipse.jetty.util.DecoratedObjectFactory</Arg>
|
||||
</Call>
|
||||
<Call name="prependServerClass">
|
||||
<Arg>-org.eclipse.jetty.server.handler.ContextHandler.</Arg>
|
||||
</Call>
|
||||
<Call name="prependServerClass">
|
||||
<Arg>-org.eclipse.jetty.server.handler.ContextHandler</Arg>
|
||||
</Call>
|
||||
<Call name="prependServerClass">
|
||||
<Arg>-org.eclipse.jetty.servlet.ServletContextHandler</Arg>
|
||||
</Call>
|
||||
</Configure>
|
|
@ -0,0 +1,40 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_3.dtd">
|
||||
|
||||
<Configure id="Server" class="org.eclipse.jetty.server.Server">
|
||||
<New id="httpConfig" class="org.eclipse.jetty.server.HttpConfiguration">
|
||||
<Set name="secureScheme">https</Set>
|
||||
<Set name="securePort"><Property name="jetty.secure.port" default="8443" /></Set>
|
||||
<Set name="outputBufferSize">32768</Set>
|
||||
<Set name="requestHeaderSize">8192</Set>
|
||||
<Set name="responseHeaderSize">8192</Set>
|
||||
<Set name="headerCacheSize">512</Set>
|
||||
</New>
|
||||
|
||||
<Call name="addConnector">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.server.ServerConnector">
|
||||
<Arg name="server"><Ref refid="Server" /></Arg>
|
||||
<Arg name="factories">
|
||||
<Array type="org.eclipse.jetty.server.ConnectionFactory">
|
||||
<Item>
|
||||
<New class="org.eclipse.jetty.server.HttpConnectionFactory">
|
||||
<Arg name="config"><Ref refid="httpConfig" /></Arg>
|
||||
</New>
|
||||
</Item>
|
||||
</Array>
|
||||
</Arg>
|
||||
<Call name="addLifeCycleListener">
|
||||
<Arg>
|
||||
<New class="org.eclipse.jetty.maven.plugin.ServerConnectorListener">
|
||||
<Set name="fileName"><Property name="jetty.port.file" default="port.txt"/></Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
<Set name="host"><Property name="jetty.host" /></Set>
|
||||
<Set name="port"><Property name="jetty.port" default="0" />0</Set>
|
||||
<Set name="idleTimeout">30000</Set>
|
||||
</New>
|
||||
</Arg>
|
||||
</Call>
|
||||
</Configure>
|
|
@ -0,0 +1,93 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2018 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 test;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.LineNumberReader;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class TestGetContent
|
||||
{
|
||||
@Test
|
||||
public void get_ping_response()
|
||||
throws Exception
|
||||
{
|
||||
|
||||
int port = getPort();
|
||||
Assert.assertTrue(port > 0);
|
||||
HttpClient httpClient = new HttpClient();
|
||||
try
|
||||
{
|
||||
httpClient.start();
|
||||
|
||||
String response = httpClient.GET( "http://localhost:" + port + "/hello?name=beer" ).getContentAsString();
|
||||
|
||||
Assert.assertEquals( "Hello", response.trim() );
|
||||
|
||||
response = httpClient.GET( "http://localhost:" + port + "/hello?name=foo" ).getContentAsString();
|
||||
|
||||
Assert.assertEquals( "Hello", response.trim() );
|
||||
}
|
||||
finally
|
||||
{
|
||||
httpClient.stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public int getPort()
|
||||
throws Exception
|
||||
{
|
||||
int attempts = 20;
|
||||
int port = -1;
|
||||
String s = System.getProperty("jetty.port.file");
|
||||
Assert.assertNotNull(s);
|
||||
File f = new File(s);
|
||||
while (true)
|
||||
{
|
||||
if (f.exists())
|
||||
{
|
||||
try (FileReader r = new FileReader(f);
|
||||
LineNumberReader lnr = new LineNumberReader(r);
|
||||
)
|
||||
{
|
||||
s = lnr.readLine();
|
||||
Assert.assertNotNull(s);
|
||||
port = Integer.parseInt(s.trim());
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (--attempts < 0)
|
||||
break;
|
||||
else
|
||||
Thread.currentThread().sleep(100);
|
||||
}
|
||||
}
|
||||
return port;
|
||||
}
|
||||
}
|
|
@ -182,7 +182,8 @@ public class ContainerTldBundleDiscoverer implements TldBundleDiscoverer
|
|||
// Class.getForName("org.apache.jasper.runtime.JspFactoryImpl")
|
||||
// however its bundles does not import the jasper package
|
||||
// so it fails. let's help things out:
|
||||
fact = (JspFactory) JettyBootstrapActivator.class.getClassLoader().loadClass(DEFAULT_JSP_FACTORY_IMPL_CLASS).newInstance();
|
||||
fact = (JspFactory) JettyBootstrapActivator.class.getClassLoader()
|
||||
.loadClass(DEFAULT_JSP_FACTORY_IMPL_CLASS).getDeclaredConstructor().newInstance();
|
||||
JspFactory.setDefaultFactory(fact);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,7 +93,8 @@ public class JSTLBundleDiscoverer implements TldBundleDiscoverer
|
|||
// Class.getForName("org.apache.jasper.runtime.JspFactoryImpl")
|
||||
// however its bundles does not import the jasper package
|
||||
// so it fails. let's help things out:
|
||||
fact = (JspFactory) JettyBootstrapActivator.class.getClassLoader().loadClass(DEFAULT_JSP_FACTORY_IMPL_CLASS).newInstance();
|
||||
fact = (JspFactory) JettyBootstrapActivator.class.getClassLoader()
|
||||
.loadClass(DEFAULT_JSP_FACTORY_IMPL_CLASS).getDeclaredConstructor().newInstance();
|
||||
JspFactory.setDefaultFactory(fact);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import org.eclipse.jetty.util.log.Log;
|
|||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.osgi.framework.BundleActivator;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
import org.osgi.framework.ServiceRegistration;
|
||||
import org.osgi.util.tracker.ServiceTracker;
|
||||
|
||||
|
@ -69,6 +70,11 @@ public class JettyBootstrapActivator implements BundleActivator
|
|||
@Override
|
||||
public void start(final BundleContext context) throws Exception
|
||||
{
|
||||
ServiceReference[] references = context.getAllServiceReferences("org.eclipse.jetty.http.HttpFieldPreEncoder", null);
|
||||
|
||||
if (references == null || references.length==0)
|
||||
LOG.warn("OSGi support for java.util.ServiceLoader may not be present. You may experience runtime errors.");
|
||||
|
||||
INSTANCE = this;
|
||||
|
||||
// track other bundles and fragments attached to this bundle that we
|
||||
|
|
|
@ -52,7 +52,8 @@ public class BundleClassLoaderHelperFactory
|
|||
try
|
||||
{
|
||||
//if a fragment has not provided their own impl
|
||||
helper = (BundleClassLoaderHelper) Class.forName(BundleClassLoaderHelper.CLASS_NAME).newInstance();
|
||||
helper = (BundleClassLoaderHelper) Class.forName(BundleClassLoaderHelper.CLASS_NAME)
|
||||
.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
|
|
|
@ -45,7 +45,8 @@ public class BundleFileLocatorHelperFactory
|
|||
try
|
||||
{
|
||||
//see if a fragment has supplied an alternative
|
||||
helper = (BundleFileLocatorHelper) Class.forName(BundleFileLocatorHelper.CLASS_NAME).newInstance();
|
||||
helper = (BundleFileLocatorHelper) Class.forName(BundleFileLocatorHelper.CLASS_NAME)
|
||||
.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
|
|
|
@ -280,27 +280,11 @@ public class PackageAdminServiceTracker implements ServiceListener
|
|||
Class<?> c = Class.forName(fragmentActivator);
|
||||
if (c != null)
|
||||
{
|
||||
BundleActivator bActivator = (BundleActivator) c.newInstance();
|
||||
BundleActivator bActivator = (BundleActivator) c.getDeclaredConstructor().newInstance();
|
||||
bActivator.start(_context);
|
||||
_activatedFragments.add(bActivator);
|
||||
}
|
||||
}
|
||||
catch (NullPointerException e)
|
||||
{
|
||||
// e.printStackTrace();
|
||||
}
|
||||
catch (InstantiationException e)
|
||||
{
|
||||
// e.printStackTrace();
|
||||
}
|
||||
catch (IllegalAccessException e)
|
||||
{
|
||||
// e.printStackTrace();
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
// e.printStackTrace();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
|
|
|
@ -610,5 +610,48 @@
|
|||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>jdk11</id>
|
||||
<activation>
|
||||
<jdk>11</jdk>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<skipTests>${skipTests}</skipTests>
|
||||
<excludes>
|
||||
<exclude>**/**/TestJettyOSGiBoot**</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<!-- if you want to run test even with jdk10/11 -->
|
||||
<profile>
|
||||
<id>alltests</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>alltests</name>
|
||||
<value>true</value>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>FOOBAR</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
|
|
@ -61,7 +61,7 @@ public class ContainerInitializer
|
|||
|
||||
try
|
||||
{
|
||||
_target = (ServletContainerInitializer)loader.loadClass(m.group(1)).newInstance();
|
||||
_target = (ServletContainerInitializer)loader.loadClass(m.group(1)).getDeclaredConstructor().newInstance();
|
||||
String[] interested = StringUtil.arrayFromString(m.group(2));
|
||||
_interestedTypes = new Class<?>[interested.length];
|
||||
for (int i=0;i<interested.length;i++)
|
||||
|
|
|
@ -85,7 +85,7 @@ public class ProxyServletFailureTest
|
|||
|
||||
public ProxyServletFailureTest(Class<?> proxyServletClass) throws Exception
|
||||
{
|
||||
this.proxyServlet = (ProxyServlet)proxyServletClass.newInstance();
|
||||
this.proxyServlet = (ProxyServlet)proxyServletClass.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
|
||||
private void prepareProxy() throws Exception
|
||||
|
|
|
@ -77,7 +77,7 @@ public class ProxyServletLoadTest
|
|||
|
||||
public ProxyServletLoadTest(Class<?> proxyServletClass) throws Exception
|
||||
{
|
||||
proxyServlet = (AbstractProxyServlet)proxyServletClass.newInstance();
|
||||
proxyServlet = (AbstractProxyServlet)proxyServletClass.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
|
||||
private void startServer(HttpServlet servlet) throws Exception
|
||||
|
|
|
@ -126,7 +126,7 @@ public class ProxyServletTest
|
|||
|
||||
public ProxyServletTest(Class<?> proxyServletClass) throws Exception
|
||||
{
|
||||
this.proxyServlet = (AbstractProxyServlet)proxyServletClass.newInstance();
|
||||
this.proxyServlet = (AbstractProxyServlet)proxyServletClass.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
|
||||
private void startServer(HttpServlet servlet) throws Exception
|
||||
|
|
|
@ -170,7 +170,7 @@ public class JDBCLoginService extends AbstractLoginService
|
|||
+ " = u."
|
||||
+ _userRoleTableRoleKey;
|
||||
|
||||
Loader.loadClass(_jdbcDriver).newInstance();
|
||||
Loader.loadClass(_jdbcDriver).getDeclaredConstructor().newInstance();
|
||||
super.doStart();
|
||||
}
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ public class AsyncContextState implements AsyncContext
|
|||
return contextHandler.getServletContext().createListener(clazz);
|
||||
try
|
||||
{
|
||||
return clazz.newInstance();
|
||||
return clazz.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
|
|
@ -24,7 +24,6 @@ import java.io.InputStream;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.nio.channels.ReadableByteChannel;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.SortedSet;
|
||||
|
@ -50,15 +49,12 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceFactory;
|
||||
|
||||
/**
|
||||
* Caching HttpContent.Factory
|
||||
*/
|
||||
public class CachedContentFactory implements HttpContent.ContentFactory
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(CachedContentFactory.class);
|
||||
private final static Map<CompressedContentFormat, CachedPrecompressedHttpContent> NO_PRECOMPRESSED = Collections.unmodifiableMap(Collections.emptyMap());
|
||||
|
||||
private final ConcurrentMap<String,CachedHttpContent> _cache;
|
||||
private final ConcurrentMap<String, CachedHttpContent> _cache;
|
||||
private final AtomicInteger _cachedSize;
|
||||
private final AtomicInteger _cachedFiles;
|
||||
private final ResourceFactory _factory;
|
||||
|
@ -66,84 +62,77 @@ public class CachedContentFactory implements HttpContent.ContentFactory
|
|||
private final MimeTypes _mimeTypes;
|
||||
private final boolean _etags;
|
||||
private final CompressedContentFormat[] _precompressedFormats;
|
||||
private final boolean _useFileMappedBuffer;
|
||||
|
||||
private int _maxCachedFileSize = 128*1024*1024;
|
||||
private int _maxCachedFiles= 2048;
|
||||
private int _maxCacheSize = 256*1024*1024;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constructor.
|
||||
* @param parent the parent resource cache
|
||||
* @param factory the resource factory
|
||||
* @param mimeTypes Mimetype to use for meta data
|
||||
* @param useFileMappedBuffer true to file memory mapped buffers
|
||||
* @param etags true to support etags
|
||||
private final boolean _useFileMappedBuffer;
|
||||
|
||||
private int _maxCachedFileSize = 128 * 1024 * 1024;
|
||||
private int _maxCachedFiles = 2048;
|
||||
private int _maxCacheSize = 256 * 1024 * 1024;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param parent the parent resource cache
|
||||
* @param factory the resource factory
|
||||
* @param mimeTypes Mimetype to use for meta data
|
||||
* @param useFileMappedBuffer true to file memory mapped buffers
|
||||
* @param etags true to support etags
|
||||
* @param precompressedFormats array of precompression formats to support
|
||||
*/
|
||||
public CachedContentFactory(CachedContentFactory parent, ResourceFactory factory, MimeTypes mimeTypes,boolean useFileMappedBuffer,boolean etags,CompressedContentFormat[] precompressedFormats)
|
||||
public CachedContentFactory(CachedContentFactory parent, ResourceFactory factory, MimeTypes mimeTypes, boolean useFileMappedBuffer, boolean etags, CompressedContentFormat[] precompressedFormats)
|
||||
{
|
||||
_factory = factory;
|
||||
_cache=new ConcurrentHashMap<String,CachedHttpContent>();
|
||||
_cachedSize=new AtomicInteger();
|
||||
_cachedFiles=new AtomicInteger();
|
||||
_mimeTypes=mimeTypes;
|
||||
_parent=parent;
|
||||
_useFileMappedBuffer=useFileMappedBuffer;
|
||||
_etags=etags;
|
||||
_precompressedFormats=precompressedFormats;
|
||||
_cache = new ConcurrentHashMap<>();
|
||||
_cachedSize = new AtomicInteger();
|
||||
_cachedFiles = new AtomicInteger();
|
||||
_mimeTypes = mimeTypes;
|
||||
_parent = parent;
|
||||
_useFileMappedBuffer = useFileMappedBuffer;
|
||||
_etags = etags;
|
||||
_precompressedFormats = precompressedFormats;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public int getCachedSize()
|
||||
{
|
||||
return _cachedSize.get();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
public int getCachedFiles()
|
||||
{
|
||||
return _cachedFiles.get();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
public int getMaxCachedFileSize()
|
||||
{
|
||||
return _maxCachedFileSize;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setMaxCachedFileSize(int maxCachedFileSize)
|
||||
{
|
||||
_maxCachedFileSize = maxCachedFileSize;
|
||||
shrinkCache();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public int getMaxCacheSize()
|
||||
{
|
||||
return _maxCacheSize;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void setMaxCacheSize(int maxCacheSize)
|
||||
{
|
||||
_maxCacheSize = maxCacheSize;
|
||||
shrinkCache();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @return Returns the maxCachedFiles.
|
||||
* @return the max number of cached files.
|
||||
*/
|
||||
public int getMaxCachedFiles()
|
||||
{
|
||||
return _maxCachedFiles;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* @param maxCachedFiles The maxCachedFiles to set.
|
||||
* @param maxCachedFiles the max number of cached files.
|
||||
*/
|
||||
public void setMaxCachedFiles(int maxCachedFiles)
|
||||
{
|
||||
|
@ -151,106 +140,94 @@ public class CachedContentFactory implements HttpContent.ContentFactory
|
|||
shrinkCache();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isUseFileMappedBuffer()
|
||||
{
|
||||
return _useFileMappedBuffer;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void flushCache()
|
||||
{
|
||||
if (_cache!=null)
|
||||
while (_cache.size() > 0)
|
||||
{
|
||||
while (_cache.size()>0)
|
||||
for (String path : _cache.keySet())
|
||||
{
|
||||
for (String path : _cache.keySet())
|
||||
{
|
||||
CachedHttpContent content = _cache.remove(path);
|
||||
if (content!=null)
|
||||
content.invalidate();
|
||||
}
|
||||
CachedHttpContent content = _cache.remove(path);
|
||||
if (content != null)
|
||||
content.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Deprecated
|
||||
public HttpContent lookup(String pathInContext)
|
||||
throws IOException
|
||||
public HttpContent lookup(String pathInContext) throws IOException
|
||||
{
|
||||
return getContent(pathInContext,_maxCachedFileSize);
|
||||
return getContent(pathInContext, _maxCachedFileSize);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get a Entry from the cache.
|
||||
* Get either a valid entry object or create a new one if possible.
|
||||
/**
|
||||
* <p>Returns an entry from the cache, or creates a new one.</p>
|
||||
*
|
||||
* @param pathInContext The key into the cache
|
||||
* @param maxBufferSize The maximum buffer to allocated for this request. For cached content, a larger buffer may have
|
||||
* previously been allocated and returned by the {@link HttpContent#getDirectBuffer()} or {@link HttpContent#getIndirectBuffer()} calls.
|
||||
* @return The entry matching <code>pathInContext</code>, or a new entry
|
||||
* if no matching entry was found. If the content exists but is not cachable,
|
||||
* then a {@link ResourceHttpContent} instance is return. If
|
||||
* @param maxBufferSize The maximum buffer size allocated for this request. For cached content, a larger buffer may have
|
||||
* previously been allocated and returned by the {@link HttpContent#getDirectBuffer()} or {@link HttpContent#getIndirectBuffer()} calls.
|
||||
* @return The entry matching {@code pathInContext}, or a new entry
|
||||
* if no matching entry was found. If the content exists but is not cacheable,
|
||||
* then a {@link ResourceHttpContent} instance is returned. If
|
||||
* the resource does not exist, then null is returned.
|
||||
* @throws IOException Problem loading the resource
|
||||
* @throws IOException if the resource cannot be retrieved
|
||||
*/
|
||||
@Override
|
||||
public HttpContent getContent(String pathInContext,int maxBufferSize)
|
||||
throws IOException
|
||||
public HttpContent getContent(String pathInContext, int maxBufferSize) throws IOException
|
||||
{
|
||||
// Is the content in this cache?
|
||||
CachedHttpContent content =_cache.get(pathInContext);
|
||||
if (content!=null && (content).isValid())
|
||||
CachedHttpContent content = _cache.get(pathInContext);
|
||||
if (content != null && (content).isValid())
|
||||
return content;
|
||||
|
||||
|
||||
// try loading the content from our factory.
|
||||
Resource resource=_factory.getResource(pathInContext);
|
||||
HttpContent loaded = load(pathInContext,resource,maxBufferSize);
|
||||
if (loaded!=null)
|
||||
Resource resource = _factory.getResource(pathInContext);
|
||||
HttpContent loaded = load(pathInContext, resource, maxBufferSize);
|
||||
if (loaded != null)
|
||||
return loaded;
|
||||
|
||||
|
||||
// Is the content in the parent cache?
|
||||
if (_parent!=null)
|
||||
if (_parent != null)
|
||||
{
|
||||
HttpContent httpContent=_parent.getContent(pathInContext,maxBufferSize);
|
||||
if (httpContent!=null)
|
||||
HttpContent httpContent = _parent.getContent(pathInContext, maxBufferSize);
|
||||
if (httpContent != null)
|
||||
return httpContent;
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* @param resource the resource to test
|
||||
* @return True if the resource is cacheable. The default implementation tests the cache sizes.
|
||||
* @return whether the resource is cacheable. The default implementation tests the cache sizes.
|
||||
*/
|
||||
protected boolean isCacheable(Resource resource)
|
||||
{
|
||||
if (_maxCachedFiles<=0)
|
||||
if (_maxCachedFiles <= 0)
|
||||
return false;
|
||||
|
||||
|
||||
long len = resource.length();
|
||||
|
||||
// Will it fit in the cache?
|
||||
return (len>0 && (_useFileMappedBuffer || (len<_maxCachedFileSize && len<_maxCacheSize)));
|
||||
return (len > 0 && (_useFileMappedBuffer || (len < _maxCachedFileSize && len < _maxCacheSize)));
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
private HttpContent load(String pathInContext, Resource resource, int maxBufferSize)
|
||||
throws IOException
|
||||
{
|
||||
if (resource == null || !resource.exists())
|
||||
return null;
|
||||
|
||||
if (resource.isDirectory())
|
||||
return new ResourceHttpContent(resource,_mimeTypes.getMimeByExtension(resource.toString()),getMaxCachedFileSize());
|
||||
return new ResourceHttpContent(resource, _mimeTypes.getMimeByExtension(resource.toString()), getMaxCachedFileSize());
|
||||
|
||||
// Will it fit in the cache?
|
||||
if (isCacheable(resource))
|
||||
{
|
||||
CachedHttpContent content = null;
|
||||
CachedHttpContent content;
|
||||
|
||||
// Look for precompressed resources
|
||||
if (_precompressedFormats.length > 0)
|
||||
|
@ -267,8 +244,8 @@ public class CachedContentFactory implements HttpContent.ContentFactory
|
|||
if (compressedResource.exists() && compressedResource.lastModified() >= resource.lastModified()
|
||||
&& compressedResource.length() < resource.length())
|
||||
{
|
||||
compressedContent = new CachedHttpContent(compressedPathInContext,compressedResource,null);
|
||||
CachedHttpContent added = _cache.putIfAbsent(compressedPathInContext,compressedContent);
|
||||
compressedContent = new CachedHttpContent(compressedPathInContext, compressedResource, null);
|
||||
CachedHttpContent added = _cache.putIfAbsent(compressedPathInContext, compressedContent);
|
||||
if (added != null)
|
||||
{
|
||||
compressedContent.invalidate();
|
||||
|
@ -277,15 +254,15 @@ public class CachedContentFactory implements HttpContent.ContentFactory
|
|||
}
|
||||
}
|
||||
if (compressedContent != null)
|
||||
precompresssedContents.put(format,compressedContent);
|
||||
precompresssedContents.put(format, compressedContent);
|
||||
}
|
||||
content = new CachedHttpContent(pathInContext,resource,precompresssedContents);
|
||||
content = new CachedHttpContent(pathInContext, resource, precompresssedContents);
|
||||
}
|
||||
else
|
||||
content = new CachedHttpContent(pathInContext,resource,null);
|
||||
content = new CachedHttpContent(pathInContext, resource, null);
|
||||
|
||||
// Add it to the cache.
|
||||
CachedHttpContent added = _cache.putIfAbsent(pathInContext,content);
|
||||
CachedHttpContent added = _cache.putIfAbsent(pathInContext, content);
|
||||
if (added != null)
|
||||
{
|
||||
content.invalidate();
|
||||
|
@ -306,167 +283,154 @@ public class CachedContentFactory implements HttpContent.ContentFactory
|
|||
String compressedPathInContext = pathInContext + format._extension;
|
||||
CachedHttpContent compressedContent = _cache.get(compressedPathInContext);
|
||||
if (compressedContent != null && compressedContent.isValid() && compressedContent.getResource().lastModified() >= resource.lastModified())
|
||||
compressedContents.put(format,compressedContent);
|
||||
compressedContents.put(format, compressedContent);
|
||||
|
||||
// Is there a precompressed resource?
|
||||
Resource compressedResource = _factory.getResource(compressedPathInContext);
|
||||
if (compressedResource.exists() && compressedResource.lastModified() >= resource.lastModified()
|
||||
&& compressedResource.length() < resource.length())
|
||||
compressedContents.put(format,
|
||||
new ResourceHttpContent(compressedResource,_mimeTypes.getMimeByExtension(compressedPathInContext),maxBufferSize));
|
||||
new ResourceHttpContent(compressedResource, _mimeTypes.getMimeByExtension(compressedPathInContext), maxBufferSize));
|
||||
}
|
||||
if (!compressedContents.isEmpty())
|
||||
return new ResourceHttpContent(resource,mt,maxBufferSize,compressedContents);
|
||||
return new ResourceHttpContent(resource, mt, maxBufferSize, compressedContents);
|
||||
}
|
||||
|
||||
return new ResourceHttpContent(resource,mt,maxBufferSize);
|
||||
return new ResourceHttpContent(resource, mt, maxBufferSize);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
private void shrinkCache()
|
||||
{
|
||||
// While we need to shrink
|
||||
while (_cache.size()>0 && (_cachedFiles.get()>_maxCachedFiles || _cachedSize.get()>_maxCacheSize))
|
||||
while (_cache.size() > 0 && (_cachedFiles.get() > _maxCachedFiles || _cachedSize.get() > _maxCacheSize))
|
||||
{
|
||||
// Scan the entire cache and generate an ordered list by last accessed time.
|
||||
SortedSet<CachedHttpContent> sorted= new TreeSet<CachedHttpContent>(
|
||||
new Comparator<CachedHttpContent>()
|
||||
{
|
||||
@Override
|
||||
public int compare(CachedHttpContent c1, CachedHttpContent c2)
|
||||
{
|
||||
if (c1._lastAccessed<c2._lastAccessed)
|
||||
return -1;
|
||||
|
||||
if (c1._lastAccessed>c2._lastAccessed)
|
||||
return 1;
|
||||
SortedSet<CachedHttpContent> sorted = new TreeSet<>((c1, c2) ->
|
||||
{
|
||||
if (c1._lastAccessed < c2._lastAccessed)
|
||||
return -1;
|
||||
|
||||
if (c1._lastAccessed > c2._lastAccessed)
|
||||
return 1;
|
||||
|
||||
if (c1._contentLengthValue < c2._contentLengthValue)
|
||||
return -1;
|
||||
|
||||
return c1._key.compareTo(c2._key);
|
||||
});
|
||||
sorted.addAll(_cache.values());
|
||||
|
||||
if (c1._contentLengthValue<c2._contentLengthValue)
|
||||
return -1;
|
||||
|
||||
return c1._key.compareTo(c2._key);
|
||||
}
|
||||
});
|
||||
for (CachedHttpContent content : _cache.values())
|
||||
sorted.add(content);
|
||||
|
||||
// Invalidate least recently used first
|
||||
for (CachedHttpContent content : sorted)
|
||||
{
|
||||
if (_cachedFiles.get()<=_maxCachedFiles && _cachedSize.get()<=_maxCacheSize)
|
||||
if (_cachedFiles.get() <= _maxCachedFiles && _cachedSize.get() <= _maxCacheSize)
|
||||
break;
|
||||
if (content==_cache.remove(content.getKey()))
|
||||
if (content == _cache.remove(content.getKey()))
|
||||
content.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
protected ByteBuffer getIndirectBuffer(Resource resource)
|
||||
{
|
||||
try
|
||||
{
|
||||
return BufferUtil.toBuffer(resource,true);
|
||||
return BufferUtil.toBuffer(resource, true);
|
||||
}
|
||||
catch(IOException|IllegalArgumentException e)
|
||||
catch (IOException | IllegalArgumentException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected ByteBuffer getMappedBuffer(Resource resource)
|
||||
{
|
||||
// Only use file mapped buffers for cached resources, otherwise too much virtual memory commitment for
|
||||
// a non shared resource. Also ignore max buffer size
|
||||
try
|
||||
{
|
||||
if (_useFileMappedBuffer && resource.getFile()!=null && resource.length()<Integer.MAX_VALUE)
|
||||
return BufferUtil.toMappedBuffer(resource.getFile());
|
||||
if (_useFileMappedBuffer && resource.getFile() != null && resource.length() < Integer.MAX_VALUE)
|
||||
return BufferUtil.toMappedBuffer(resource.getFile());
|
||||
}
|
||||
catch(IOException|IllegalArgumentException e)
|
||||
catch (IOException | IllegalArgumentException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
protected ByteBuffer getDirectBuffer(Resource resource)
|
||||
{
|
||||
try
|
||||
{
|
||||
return BufferUtil.toBuffer(resource,true);
|
||||
return BufferUtil.toBuffer(resource, true);
|
||||
}
|
||||
catch(IOException|IllegalArgumentException e)
|
||||
catch (IOException | IllegalArgumentException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "ResourceCache["+_parent+","+_factory+"]@"+hashCode();
|
||||
return "ResourceCache[" + _parent + "," + _factory + "]@" + hashCode();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
/** MetaData associated with a context Resource.
|
||||
|
||||
/**
|
||||
* MetaData associated with a context Resource.
|
||||
*/
|
||||
public class CachedHttpContent implements HttpContent
|
||||
{
|
||||
final String _key;
|
||||
final Resource _resource;
|
||||
final int _contentLengthValue;
|
||||
final HttpField _contentType;
|
||||
final String _characterEncoding;
|
||||
final MimeTypes.Type _mimeType;
|
||||
final HttpField _contentLength;
|
||||
final HttpField _lastModified;
|
||||
final long _lastModifiedValue;
|
||||
final HttpField _etag;
|
||||
final Map<CompressedContentFormat, CachedPrecompressedHttpContent> _precompressed;
|
||||
|
||||
volatile long _lastAccessed;
|
||||
AtomicReference<ByteBuffer> _indirectBuffer=new AtomicReference<ByteBuffer>();
|
||||
AtomicReference<ByteBuffer> _directBuffer=new AtomicReference<ByteBuffer>();
|
||||
private final String _key;
|
||||
private final Resource _resource;
|
||||
private final int _contentLengthValue;
|
||||
private final HttpField _contentType;
|
||||
private final String _characterEncoding;
|
||||
private final MimeTypes.Type _mimeType;
|
||||
private final HttpField _contentLength;
|
||||
private final HttpField _lastModified;
|
||||
private final long _lastModifiedValue;
|
||||
private final HttpField _etag;
|
||||
private final Map<CompressedContentFormat, CachedPrecompressedHttpContent> _precompressed;
|
||||
private final AtomicReference<ByteBuffer> _indirectBuffer = new AtomicReference<>();
|
||||
private final AtomicReference<ByteBuffer> _directBuffer = new AtomicReference<>();
|
||||
private final AtomicReference<ByteBuffer> _mappedBuffer = new AtomicReference<>();
|
||||
private volatile long _lastAccessed;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
CachedHttpContent(String pathInContext,Resource resource,Map<CompressedContentFormat, CachedHttpContent> precompressedResources)
|
||||
CachedHttpContent(String pathInContext, Resource resource, Map<CompressedContentFormat, CachedHttpContent> precompressedResources)
|
||||
{
|
||||
_key=pathInContext;
|
||||
_resource=resource;
|
||||
_key = pathInContext;
|
||||
_resource = resource;
|
||||
|
||||
String contentType = _mimeTypes.getMimeByExtension(_resource.toString());
|
||||
_contentType=contentType==null?null:new PreEncodedHttpField(HttpHeader.CONTENT_TYPE,contentType);
|
||||
_characterEncoding = _contentType==null?null:MimeTypes.getCharsetFromContentType(contentType);
|
||||
_mimeType = _contentType==null?null:MimeTypes.CACHE.get(MimeTypes.getContentTypeWithoutCharset(contentType));
|
||||
|
||||
boolean exists=resource.exists();
|
||||
_lastModifiedValue=exists?resource.lastModified():-1L;
|
||||
_lastModified=_lastModifiedValue==-1?null
|
||||
:new PreEncodedHttpField(HttpHeader.LAST_MODIFIED,DateGenerator.formatDate(_lastModifiedValue));
|
||||
|
||||
_contentLengthValue=exists?(int)resource.length():0;
|
||||
_contentLength=new PreEncodedHttpField(HttpHeader.CONTENT_LENGTH,Long.toString(_contentLengthValue));
|
||||
|
||||
if (_cachedFiles.incrementAndGet()>_maxCachedFiles)
|
||||
_contentType = contentType == null ? null : new PreEncodedHttpField(HttpHeader.CONTENT_TYPE, contentType);
|
||||
_characterEncoding = _contentType == null ? null : MimeTypes.getCharsetFromContentType(contentType);
|
||||
_mimeType = _contentType == null ? null : MimeTypes.CACHE.get(MimeTypes.getContentTypeWithoutCharset(contentType));
|
||||
|
||||
boolean exists = resource.exists();
|
||||
_lastModifiedValue = exists ? resource.lastModified() : -1L;
|
||||
_lastModified = _lastModifiedValue == -1 ? null
|
||||
: new PreEncodedHttpField(HttpHeader.LAST_MODIFIED, DateGenerator.formatDate(_lastModifiedValue));
|
||||
|
||||
_contentLengthValue = exists ? (int)resource.length() : 0;
|
||||
_contentLength = new PreEncodedHttpField(HttpHeader.CONTENT_LENGTH, Long.toString(_contentLengthValue));
|
||||
|
||||
if (_cachedFiles.incrementAndGet() > _maxCachedFiles)
|
||||
shrinkCache();
|
||||
|
||||
_lastAccessed=System.currentTimeMillis();
|
||||
|
||||
_etag=CachedContentFactory.this._etags?new PreEncodedHttpField(HttpHeader.ETAG,resource.getWeakETag()):null;
|
||||
|
||||
_lastAccessed = System.currentTimeMillis();
|
||||
|
||||
_etag = CachedContentFactory.this._etags ? new PreEncodedHttpField(HttpHeader.ETAG, resource.getWeakETag()) : null;
|
||||
|
||||
if (precompressedResources != null)
|
||||
{
|
||||
_precompressed = new HashMap<>(precompressedResources.size());
|
||||
for (Map.Entry<CompressedContentFormat, CachedHttpContent> entry : precompressedResources.entrySet())
|
||||
{
|
||||
_precompressed.put(entry.getKey(),new CachedPrecompressedHttpContent(this,entry.getValue(),entry.getKey()));
|
||||
_precompressed.put(entry.getKey(), new CachedPrecompressedHttpContent(this, entry.getValue(), entry.getKey()));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -474,237 +438,223 @@ public class CachedContentFactory implements HttpContent.ContentFactory
|
|||
_precompressed = NO_PRECOMPRESSED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String getKey()
|
||||
{
|
||||
return _key;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isCached()
|
||||
{
|
||||
return _key!=null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean isMiss()
|
||||
{
|
||||
return false;
|
||||
return _key != null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public Resource getResource()
|
||||
{
|
||||
return _resource;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public HttpField getETag()
|
||||
{
|
||||
return _etag;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String getETagValue()
|
||||
{
|
||||
return _etag.getValue();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
boolean isValid()
|
||||
{
|
||||
if (_lastModifiedValue==_resource.lastModified() && _contentLengthValue==_resource.length())
|
||||
if (_lastModifiedValue == _resource.lastModified() && _contentLengthValue == _resource.length())
|
||||
{
|
||||
_lastAccessed=System.currentTimeMillis();
|
||||
_lastAccessed = System.currentTimeMillis();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this==_cache.remove(_key))
|
||||
if (this == _cache.remove(_key))
|
||||
invalidate();
|
||||
return false;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
protected void invalidate()
|
||||
{
|
||||
ByteBuffer indirect=_indirectBuffer.get();
|
||||
if (indirect!=null && _indirectBuffer.compareAndSet(indirect,null))
|
||||
ByteBuffer indirect = _indirectBuffer.getAndSet(null);
|
||||
if (indirect != null)
|
||||
_cachedSize.addAndGet(-BufferUtil.length(indirect));
|
||||
|
||||
ByteBuffer direct=_directBuffer.get();
|
||||
|
||||
if (direct!=null && !BufferUtil.isMappedBuffer(direct) && _directBuffer.compareAndSet(direct,null))
|
||||
|
||||
ByteBuffer direct = _directBuffer.getAndSet(null);
|
||||
if (direct != null)
|
||||
_cachedSize.addAndGet(-BufferUtil.length(direct));
|
||||
|
||||
|
||||
_mappedBuffer.getAndSet(null);
|
||||
|
||||
_cachedFiles.decrementAndGet();
|
||||
_resource.close();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public HttpField getLastModified()
|
||||
{
|
||||
return _lastModified;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
@Override
|
||||
public String getLastModifiedValue()
|
||||
{
|
||||
return _lastModified==null?null:_lastModified.getValue();
|
||||
return _lastModified == null ? null : _lastModified.getValue();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public HttpField getContentType()
|
||||
{
|
||||
return _contentType;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
@Override
|
||||
public String getContentTypeValue()
|
||||
{
|
||||
return _contentType==null?null:_contentType.getValue();
|
||||
return _contentType == null ? null : _contentType.getValue();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public HttpField getContentEncoding()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String getContentEncodingValue()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCharacterEncoding()
|
||||
{
|
||||
return _characterEncoding;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public Type getMimeType()
|
||||
{
|
||||
return _mimeType;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public void release()
|
||||
{
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public ByteBuffer getIndirectBuffer()
|
||||
{
|
||||
ByteBuffer buffer = _indirectBuffer.get();
|
||||
if (buffer==null)
|
||||
if (buffer == null)
|
||||
{
|
||||
ByteBuffer buffer2=CachedContentFactory.this.getIndirectBuffer(_resource);
|
||||
|
||||
if (buffer2==null)
|
||||
LOG.warn("Could not load "+this);
|
||||
else if (_indirectBuffer.compareAndSet(null,buffer2))
|
||||
ByteBuffer buffer2 = CachedContentFactory.this.getIndirectBuffer(_resource);
|
||||
|
||||
if (buffer2 == null)
|
||||
LOG.warn("Could not load " + this);
|
||||
else if (_indirectBuffer.compareAndSet(null, buffer2))
|
||||
{
|
||||
buffer=buffer2;
|
||||
if (_cachedSize.addAndGet(BufferUtil.length(buffer))>_maxCacheSize)
|
||||
buffer = buffer2;
|
||||
if (_cachedSize.addAndGet(BufferUtil.length(buffer)) > _maxCacheSize)
|
||||
shrinkCache();
|
||||
}
|
||||
else
|
||||
buffer=_indirectBuffer.get();
|
||||
buffer = _indirectBuffer.get();
|
||||
}
|
||||
if (buffer==null)
|
||||
if (buffer == null)
|
||||
return null;
|
||||
return buffer.slice();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
@Override
|
||||
public ByteBuffer getDirectBuffer()
|
||||
{
|
||||
ByteBuffer buffer = _directBuffer.get();
|
||||
if (buffer==null)
|
||||
ByteBuffer buffer = _mappedBuffer.get();
|
||||
if (buffer == null)
|
||||
buffer = _directBuffer.get();
|
||||
if (buffer == null)
|
||||
{
|
||||
ByteBuffer mapped = CachedContentFactory.this.getMappedBuffer(_resource);
|
||||
ByteBuffer direct = mapped==null?CachedContentFactory.this.getDirectBuffer(_resource):mapped;
|
||||
|
||||
if (direct==null)
|
||||
LOG.warn("Could not load "+this);
|
||||
else if (_directBuffer.compareAndSet(null,direct))
|
||||
if (mapped != null)
|
||||
{
|
||||
buffer=direct;
|
||||
if (mapped==null && _cachedSize.addAndGet(BufferUtil.length(buffer))>_maxCacheSize)
|
||||
shrinkCache();
|
||||
if (_mappedBuffer.compareAndSet(null, mapped))
|
||||
buffer = mapped;
|
||||
else
|
||||
buffer = _mappedBuffer.get();
|
||||
}
|
||||
else
|
||||
buffer=_directBuffer.get();
|
||||
{
|
||||
ByteBuffer direct = CachedContentFactory.this.getDirectBuffer(_resource);
|
||||
if (direct != null)
|
||||
{
|
||||
if (_directBuffer.compareAndSet(null, direct))
|
||||
{
|
||||
buffer = direct;
|
||||
if (_cachedSize.addAndGet(BufferUtil.length(buffer)) > _maxCacheSize)
|
||||
shrinkCache();
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer = _directBuffer.get();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.warn("Could not load " + this);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (buffer==null)
|
||||
return null;
|
||||
return buffer.asReadOnlyBuffer();
|
||||
return buffer == null ? null : buffer.asReadOnlyBuffer();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public HttpField getContentLength()
|
||||
{
|
||||
return _contentLength;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
||||
@Override
|
||||
public long getContentLengthValue()
|
||||
{
|
||||
return _contentLengthValue;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public InputStream getInputStream() throws IOException
|
||||
{
|
||||
ByteBuffer indirect = getIndirectBuffer();
|
||||
if (indirect!=null && indirect.hasArray())
|
||||
return new ByteArrayInputStream(indirect.array(),indirect.arrayOffset()+indirect.position(),indirect.remaining());
|
||||
|
||||
if (indirect != null && indirect.hasArray())
|
||||
return new ByteArrayInputStream(indirect.array(), indirect.arrayOffset() + indirect.position(), indirect.remaining());
|
||||
|
||||
return _resource.getInputStream();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReadableByteChannel getReadableByteChannel() throws IOException
|
||||
{
|
||||
return _resource.getReadableByteChannel();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("CachedContent@%x{r=%s,e=%b,lm=%s,ct=%s,c=%d}",hashCode(),_resource,_resource.exists(),_lastModified,_contentType,_precompressed.size());
|
||||
return String.format("CachedContent@%x{r=%s,e=%b,lm=%s,ct=%s,c=%d}", hashCode(), _resource, _resource.exists(), _lastModified, _contentType, _precompressed.size());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
@Override
|
||||
public Map<CompressedContentFormat,? extends HttpContent> getPrecompressedContents()
|
||||
public Map<CompressedContentFormat, ? extends HttpContent> getPrecompressedContents()
|
||||
{
|
||||
if (_precompressed.size()==0)
|
||||
if (_precompressed.size() == 0)
|
||||
return null;
|
||||
Map<CompressedContentFormat, CachedPrecompressedHttpContent> ret=_precompressed;
|
||||
for (Map.Entry<CompressedContentFormat, CachedPrecompressedHttpContent> entry:_precompressed.entrySet())
|
||||
Map<CompressedContentFormat, CachedPrecompressedHttpContent> ret = _precompressed;
|
||||
for (Map.Entry<CompressedContentFormat, CachedPrecompressedHttpContent> entry : _precompressed.entrySet())
|
||||
{
|
||||
if (!entry.getValue().isValid())
|
||||
{
|
||||
|
@ -717,22 +667,19 @@ public class CachedContentFactory implements HttpContent.ContentFactory
|
|||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
public class CachedPrecompressedHttpContent extends PrecompressedHttpContent
|
||||
{
|
||||
private final CachedHttpContent _content;
|
||||
private final CachedHttpContent _content;
|
||||
private final CachedHttpContent _precompressedContent;
|
||||
private final HttpField _etag;
|
||||
|
||||
CachedPrecompressedHttpContent(CachedHttpContent content, CachedHttpContent precompressedContent, CompressedContentFormat format)
|
||||
{
|
||||
super(content,precompressedContent,format);
|
||||
_content=content;
|
||||
_precompressedContent=precompressedContent;
|
||||
|
||||
_etag=(CachedContentFactory.this._etags)?new PreEncodedHttpField(HttpHeader.ETAG,_content.getResource().getWeakETag(format._etag)):null;
|
||||
super(content, precompressedContent, format);
|
||||
_content = content;
|
||||
_precompressedContent = precompressedContent;
|
||||
|
||||
_etag = (CachedContentFactory.this._etags) ? new PreEncodedHttpField(HttpHeader.ETAG, _content.getResource().getWeakETag(format._etag)) : null;
|
||||
}
|
||||
|
||||
public boolean isValid()
|
||||
|
@ -743,7 +690,7 @@ public class CachedContentFactory implements HttpContent.ContentFactory
|
|||
@Override
|
||||
public HttpField getETag()
|
||||
{
|
||||
if (_etag!=null)
|
||||
if (_etag != null)
|
||||
return _etag;
|
||||
return super.getETag();
|
||||
}
|
||||
|
@ -751,16 +698,15 @@ public class CachedContentFactory implements HttpContent.ContentFactory
|
|||
@Override
|
||||
public String getETagValue()
|
||||
{
|
||||
if (_etag!=null)
|
||||
if (_etag != null)
|
||||
return _etag.getValue();
|
||||
return super.getETagValue();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "Cached"+super.toString();
|
||||
return "Cached" + super.toString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2532,7 +2532,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
|
||||
public <T> T createInstance (Class<T> clazz) throws Exception
|
||||
{
|
||||
T o = clazz.newInstance();
|
||||
T o = clazz.getDeclaredConstructor().newInstance();
|
||||
return o;
|
||||
}
|
||||
|
||||
|
@ -2829,13 +2829,9 @@ public class ContextHandler extends ScopedHandler implements Attributes, Gracefu
|
|||
{
|
||||
try
|
||||
{
|
||||
return clazz.newInstance();
|
||||
return clazz.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
catch (InstantiationException e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
catch (IllegalAccessException e)
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ServletException(e);
|
||||
}
|
||||
|
|
|
@ -247,7 +247,7 @@ public class ContextHandlerCollection extends HandlerCollection
|
|||
{
|
||||
try
|
||||
{
|
||||
ContextHandler context = _contextClass.newInstance();
|
||||
ContextHandler context = _contextClass.getDeclaredConstructor().newInstance();
|
||||
context.setContextPath(contextPath);
|
||||
context.setResourceBase(resourceBase);
|
||||
addHandler(context);
|
||||
|
|
|
@ -327,7 +327,7 @@ public class RequestLogTest
|
|||
{
|
||||
try
|
||||
{
|
||||
throw (Throwable)(Class.forName(value).newInstance());
|
||||
throw (Throwable)(Class.forName(value).getDeclaredConstructor().newInstance());
|
||||
}
|
||||
catch(ServletException | IOException | Error | RuntimeException e)
|
||||
{
|
||||
|
|
|
@ -120,7 +120,7 @@ public class FilterHolder extends Holder<Filter>
|
|||
ServletContext context=_servletHandler.getServletContext();
|
||||
_filter=(context instanceof ServletContextHandler.Context)
|
||||
?((ServletContextHandler.Context)context).createFilter(getHeldClass())
|
||||
:getHeldClass().newInstance();
|
||||
:getHeldClass().getDeclaredConstructor().newInstance();
|
||||
}
|
||||
catch (ServletException se)
|
||||
{
|
||||
|
|
|
@ -327,7 +327,7 @@ public class ServletContextHandler extends ContextHandler
|
|||
{
|
||||
try
|
||||
{
|
||||
return (SecurityHandler)_defaultSecurityHandlerClass.newInstance();
|
||||
return _defaultSecurityHandlerClass.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.eclipse.jetty.servlet;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
@ -1283,15 +1284,18 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
|
|||
* @throws ServletException if unable to create a new instance
|
||||
* @throws IllegalAccessException if not allowed to create a new instance
|
||||
* @throws InstantiationException if creating new instance resulted in error
|
||||
* @throws NoSuchMethodException if creating new instance resulted in error
|
||||
* @throws InvocationTargetException If creating new instance throws an exception
|
||||
*/
|
||||
protected Servlet newInstance() throws ServletException, IllegalAccessException, InstantiationException
|
||||
protected Servlet newInstance() throws ServletException, IllegalAccessException, InstantiationException,
|
||||
NoSuchMethodException, InvocationTargetException
|
||||
{
|
||||
try
|
||||
{
|
||||
ServletContext ctx = getServletHandler().getServletContext();
|
||||
if (ctx instanceof ServletContextHandler.Context)
|
||||
return ((ServletContextHandler.Context)ctx).createServlet(getHeldClass());
|
||||
return getHeldClass().newInstance();
|
||||
return getHeldClass().getDeclaredConstructor().newInstance();
|
||||
}
|
||||
catch (ServletException se)
|
||||
{
|
||||
|
@ -1300,6 +1304,10 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
|
|||
throw (InstantiationException)cause;
|
||||
if (cause instanceof IllegalAccessException)
|
||||
throw (IllegalAccessException)cause;
|
||||
if (cause instanceof NoSuchMethodException)
|
||||
throw (NoSuchMethodException)cause;
|
||||
if (cause instanceof InvocationTargetException)
|
||||
throw (InvocationTargetException)cause;
|
||||
throw se;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
|
||||
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.xml.ConfigurationProcessorFactory</Provide-Capability>
|
||||
</instructions>
|
||||
</configuration>
|
||||
|
|
|
@ -18,11 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.start;
|
||||
|
||||
import static org.hamcrest.Matchers.anyOf;
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
|
@ -37,6 +32,10 @@ import org.eclipse.jetty.toolchain.test.TestingDir;
|
|||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
public class ModulesTest
|
||||
{
|
||||
private final static String TEST_SOURCE = "<test>";
|
||||
|
@ -70,8 +69,8 @@ public class ModulesTest
|
|||
modules.registerAll();
|
||||
|
||||
// Check versions
|
||||
assertThat("java.version.platform", args.getProperties().getString("java.version.platform"), //
|
||||
anyOf(equalTo("8"),equalTo("9"),equalTo( "10" )));
|
||||
String platformProperty = args.getProperties().getString("java.version.platform");
|
||||
assertThat("java.version.platform", Integer.parseInt(platformProperty), greaterThanOrEqualTo(8));
|
||||
|
||||
List<String> moduleNames = new ArrayList<>();
|
||||
for (Module mod : modules)
|
||||
|
|
|
@ -709,7 +709,7 @@ public class JSON
|
|||
{
|
||||
try
|
||||
{
|
||||
Convertible conv = (Convertible)type.newInstance();
|
||||
Convertible conv = (Convertible)type.getDeclaredConstructor().newInstance();
|
||||
conv.fromJSON(map);
|
||||
return conv;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,8 @@ public class JSONCollectionConvertor implements JSON.Convertor
|
|||
{
|
||||
try
|
||||
{
|
||||
Collection result = (Collection)Loader.loadClass((String)object.get("class")).newInstance();
|
||||
Collection result = (Collection)Loader.loadClass((String)object.get("class"))
|
||||
.getDeclaredConstructor().newInstance();
|
||||
Collections.addAll(result, (Object[])object.get("list"));
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -182,7 +182,7 @@ public class JSONPojoConvertor implements JSON.Convertor
|
|||
Object obj = null;
|
||||
try
|
||||
{
|
||||
obj = _pojoClass.newInstance();
|
||||
obj = _pojoClass.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
|
|
|
@ -26,7 +26,6 @@ import java.io.RandomAccessFile;
|
|||
import java.nio.Buffer;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.nio.channels.FileChannel.MapMode;
|
||||
import java.nio.charset.Charset;
|
||||
|
@ -922,25 +921,17 @@ public class BufferUtil
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param buffer the buffer to test
|
||||
* @return {@code false}
|
||||
* @deprecated don't use - there is no way to reliably tell if a ByteBuffer is mapped.
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean isMappedBuffer(ByteBuffer buffer)
|
||||
{
|
||||
if (!(buffer instanceof MappedByteBuffer))
|
||||
return false;
|
||||
MappedByteBuffer mapped = (MappedByteBuffer) buffer;
|
||||
|
||||
try
|
||||
{
|
||||
// Check if it really is a mapped buffer
|
||||
mapped.isLoaded();
|
||||
return true;
|
||||
}
|
||||
catch(UnsupportedOperationException e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static ByteBuffer toBuffer(Resource resource,boolean direct) throws IOException
|
||||
{
|
||||
int len=(int)resource.length();
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
package org.eclipse.jetty.util;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
|
@ -58,13 +59,14 @@ public class DecoratedObjectFactory implements Iterable<Decorator>
|
|||
this.decorators.clear();
|
||||
}
|
||||
|
||||
public <T> T createInstance(Class<T> clazz) throws InstantiationException, IllegalAccessException
|
||||
public <T> T createInstance(Class<T> clazz) throws InstantiationException, IllegalAccessException,
|
||||
NoSuchMethodException, InvocationTargetException
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("Creating Instance: " + clazz);
|
||||
}
|
||||
T o = clazz.newInstance();
|
||||
T o = clazz.getDeclaredConstructor().newInstance();
|
||||
return decorate(o);
|
||||
}
|
||||
|
||||
|
|
|
@ -77,8 +77,8 @@ public class IncludeExcludeSet<T,P> implements Predicate<P>
|
|||
{
|
||||
try
|
||||
{
|
||||
_includes = setClass.newInstance();
|
||||
_excludes = setClass.newInstance();
|
||||
_includes = setClass.getDeclaredConstructor().newInstance();
|
||||
_excludes = setClass.getDeclaredConstructor().newInstance();
|
||||
|
||||
if(_includes instanceof Predicate)
|
||||
{
|
||||
|
@ -98,7 +98,11 @@ public class IncludeExcludeSet<T,P> implements Predicate<P>
|
|||
_excludePredicate = new SetContainsPredicate(_excludes);
|
||||
}
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
catch (RuntimeException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
|
|
@ -175,7 +175,7 @@ public class Log
|
|||
Class<?> log_class = __logClass==null?null:Loader.loadClass(Log.class,__logClass);
|
||||
if (LOG == null || (log_class!=null && !LOG.getClass().equals(log_class)))
|
||||
{
|
||||
LOG = (Logger)log_class.newInstance();
|
||||
LOG = (Logger)log_class.getDeclaredConstructor().newInstance();
|
||||
if(announce)
|
||||
{
|
||||
LOG.debug("Logging to {} via {}", LOG, log_class.getName());
|
||||
|
|
|
@ -120,7 +120,7 @@ public class ReservedThreadExecutor extends AbstractLifeCycle implements TryExec
|
|||
@ManagedAttribute(value = "available reserved threads", readonly = true)
|
||||
public int getAvailable()
|
||||
{
|
||||
return _size.get();
|
||||
return _stack.size();
|
||||
}
|
||||
|
||||
@ManagedAttribute(value = "pending reserved threads", readonly = true)
|
||||
|
|
|
@ -19,20 +19,10 @@
|
|||
package org.eclipse.jetty.util;
|
||||
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.BufferOverflowException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
|
@ -42,6 +32,12 @@ import org.junit.Assert;
|
|||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.containsString;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class BufferUtilTest
|
||||
{
|
||||
@Test
|
||||
|
@ -352,39 +348,4 @@ public class BufferUtilTest
|
|||
BufferUtil.writeTo(buffer.asReadOnlyBuffer(), out);
|
||||
assertThat("Bytes in out equal bytes in buffer", Arrays.equals(bytes, out.toByteArray()), is(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMappedFile() throws Exception
|
||||
{
|
||||
String data="Now is the time for all good men to come to the aid of the party";
|
||||
File file = File.createTempFile("test",".txt");
|
||||
file.deleteOnExit();
|
||||
try(FileWriter out = new FileWriter(file))
|
||||
{
|
||||
out.write(data);
|
||||
}
|
||||
|
||||
ByteBuffer mapped = BufferUtil.toMappedBuffer(file);
|
||||
assertEquals(data,BufferUtil.toString(mapped));
|
||||
assertTrue(BufferUtil.isMappedBuffer(mapped));
|
||||
|
||||
ByteBuffer direct = BufferUtil.allocateDirect(data.length());
|
||||
BufferUtil.clearToFill(direct);
|
||||
direct.put(data.getBytes(StandardCharsets.ISO_8859_1));
|
||||
BufferUtil.flipToFlush(direct, 0);
|
||||
assertEquals(data,BufferUtil.toString(direct));
|
||||
assertFalse(BufferUtil.isMappedBuffer(direct));
|
||||
|
||||
ByteBuffer slice = direct.slice();
|
||||
assertEquals(data,BufferUtil.toString(slice));
|
||||
assertFalse(BufferUtil.isMappedBuffer(slice));
|
||||
|
||||
ByteBuffer duplicate = direct.duplicate();
|
||||
assertEquals(data,BufferUtil.toString(duplicate));
|
||||
assertFalse(BufferUtil.isMappedBuffer(duplicate));
|
||||
|
||||
ByteBuffer readonly = direct.asReadOnlyBuffer();
|
||||
assertEquals(data,BufferUtil.toString(readonly));
|
||||
assertFalse(BufferUtil.isMappedBuffer(readonly));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,13 +18,8 @@
|
|||
|
||||
package org.eclipse.jetty.util.thread;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
@ -36,6 +31,10 @@ import org.junit.Before;
|
|||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class ReservedThreadExecutorTest
|
||||
{
|
||||
private static final int SIZE = 2;
|
||||
|
@ -71,7 +70,7 @@ public class ReservedThreadExecutorTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testStarted() throws Exception
|
||||
public void testStarted()
|
||||
{
|
||||
// Reserved threads are lazily started.
|
||||
assertThat(_executor._queue.size(), is(0));
|
||||
|
@ -167,19 +166,6 @@ public class ReservedThreadExecutorTest
|
|||
assertThat(_reservedExecutor.getAvailable(),is(0));
|
||||
}
|
||||
|
||||
protected void waitForNoPending() throws InterruptedException
|
||||
{
|
||||
long started = System.nanoTime();
|
||||
while (_reservedExecutor.getPending() > 0)
|
||||
{
|
||||
long elapsed = System.nanoTime() - started;
|
||||
if (elapsed > TimeUnit.SECONDS.toNanos(10))
|
||||
Assert.fail("pending="+_reservedExecutor.getPending());
|
||||
Thread.sleep(10);
|
||||
}
|
||||
assertThat(_reservedExecutor.getPending(), is(0));
|
||||
}
|
||||
|
||||
protected void waitForAvailable(int size) throws InterruptedException
|
||||
{
|
||||
long started = System.nanoTime();
|
||||
|
@ -248,7 +234,6 @@ public class ReservedThreadExecutorTest
|
|||
reserved.start();
|
||||
|
||||
final int LOOPS = 1000000;
|
||||
final Random random = new Random();
|
||||
final AtomicInteger executions = new AtomicInteger(LOOPS);
|
||||
final CountDownLatch executed = new CountDownLatch(executions.get());
|
||||
final AtomicInteger usedReserved = new AtomicInteger(0);
|
||||
|
|
|
@ -1032,7 +1032,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
|
|||
_configurationClasses.addAll(Configuration.ClassList.serverDefault(getServer()));
|
||||
}
|
||||
for (String configClass : _configurationClasses)
|
||||
_configurations.add((Configuration)Loader.loadClass(configClass).newInstance());
|
||||
_configurations.add((Configuration)Loader.loadClass(configClass).getDeclaredConstructor().newInstance());
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
|
|
|
@ -61,7 +61,7 @@ public class WebAppClassLoaderUrlStreamTest extends WebAppClassLoaderTest
|
|||
try
|
||||
{
|
||||
Class<?> clazz = Class.forName(className, false, classLoader);
|
||||
handler = (URLStreamHandler) clazz.newInstance();
|
||||
handler = (URLStreamHandler) clazz.getDeclaredConstructor().newInstance();
|
||||
break;
|
||||
}
|
||||
catch (Exception ignore)
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
<instructions>
|
||||
<Bundle-Description>javax.websocket.client Implementation</Bundle-Description>
|
||||
<Export-Package>org.eclipse.jetty.websocket.jsr356.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"</Export-Package>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
|
||||
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=javax.websocket.ContainerProvider</Provide-Capability>
|
||||
</instructions>
|
||||
</configuration>
|
||||
|
|
|
@ -419,11 +419,11 @@ public class ClientContainer extends ContainerLifeCycle implements WebSocketCont
|
|||
{
|
||||
try
|
||||
{
|
||||
return newClientEndpointInstance(endpointClass.newInstance(),config);
|
||||
return newClientEndpointInstance(endpointClass.getDeclaredConstructor().newInstance(),config);
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InvalidWebSocketException("Unable to instantiate websocket: " + endpointClass.getClass());
|
||||
throw new InvalidWebSocketException("Unable to instantiate websocket: " + endpointClass.getClass(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -194,9 +194,9 @@ public class DecoderFactory implements Configurable
|
|||
Decoder decoder = containerScope.getObjectFactory().createInstance(decoderClass);
|
||||
return new Wrapper(decoder,metadata);
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IllegalStateException("Unable to instantiate Decoder: " + decoderClass.getName());
|
||||
throw new IllegalStateException("Unable to instantiate Decoder: " + decoderClass.getName(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -181,9 +181,9 @@ public class EncoderFactory implements Configurable
|
|||
Encoder encoder = containerScope.getObjectFactory().createInstance(encoderClass);
|
||||
return new Wrapper(encoder,metadata);
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IllegalStateException("Unable to instantiate Encoder: " + encoderClass.getName());
|
||||
throw new IllegalStateException("Unable to instantiate Encoder: " + encoderClass.getName(),e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,9 +60,9 @@ public class AnnotatedClientEndpointConfig implements ClientEndpointConfig
|
|||
{
|
||||
try
|
||||
{
|
||||
this.configurator = anno.configurator().newInstance();
|
||||
this.configurator = anno.configurator().getDeclaredConstructor( ).newInstance();
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
catch (Exception e)
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Unable to instantiate ClientEndpoint.configurator() of ");
|
||||
|
|
|
@ -109,7 +109,7 @@ public class OnCloseTest
|
|||
// Build up EventDriver
|
||||
WebSocketPolicy policy = WebSocketPolicy.newClientPolicy();
|
||||
ClientEndpointConfig config = metadata.getConfig();
|
||||
TrackingSocket endpoint = (TrackingSocket)testcase.closeClass.newInstance();
|
||||
TrackingSocket endpoint = (TrackingSocket)testcase.closeClass.getDeclaredConstructor().newInstance();
|
||||
EndpointInstance ei = new EndpointInstance(endpoint,config,metadata);
|
||||
JsrEvents<ClientEndpoint, ClientEndpointConfig> jsrevents = new JsrEvents<>(metadata);
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@
|
|||
<instructions>
|
||||
<Bundle-Description>javax.websocket.server Implementation</Bundle-Description>
|
||||
<Export-Package>org.eclipse.jetty.websocket.jsr356.server.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"</Export-Package>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
|
||||
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=javax.servlet.ServletContainerInitializer,osgi.serviceloader;osgi.serviceloader=javax.websocket.server.ServerEndpointConfig$Configurator</Provide-Capability>
|
||||
</instructions>
|
||||
</configuration>
|
||||
|
|
|
@ -129,9 +129,9 @@ public class AnnotatedServerEndpointConfig implements ServerEndpointConfig
|
|||
{
|
||||
try
|
||||
{
|
||||
cfgr = anno.configurator().newInstance();
|
||||
cfgr = anno.configurator().getDeclaredConstructor( ).newInstance();
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
catch (Exception e)
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Unable to instantiate ClientEndpoint.configurator() of ");
|
||||
|
|
|
@ -69,9 +69,9 @@ public final class ContainerDefaultConfigurator extends Configurator
|
|||
{
|
||||
// Since this is started via a ServiceLoader, this class has no Scope or context
|
||||
// that can be used to obtain a ObjectFactory from.
|
||||
return endpointClass.newInstance();
|
||||
return endpointClass.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
catch (IllegalAccessException e)
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new InstantiationException(String.format("%s: %s",e.getClass().getName(),e.getMessage()));
|
||||
}
|
||||
|
|
|
@ -255,7 +255,7 @@ public class WebSocketServerContainerInitializer implements ServletContainerInit
|
|||
}
|
||||
try
|
||||
{
|
||||
ServerApplicationConfig config = clazz.newInstance();
|
||||
ServerApplicationConfig config = clazz.getDeclaredConstructor( ).newInstance();
|
||||
|
||||
Set<ServerEndpointConfig> seconfigs = config.getEndpointConfigs(discoveredExtendedEndpoints);
|
||||
if (seconfigs != null)
|
||||
|
@ -271,7 +271,7 @@ public class WebSocketServerContainerInitializer implements ServletContainerInit
|
|||
deployableAnnotatedEndpoints.addAll(annotatedClasses);
|
||||
}
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ServletException("Unable to instantiate: " + clazz.getName(),e);
|
||||
}
|
||||
|
|
|
@ -59,7 +59,7 @@
|
|||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Require-Capability>osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.websocket.api.extensions.Extension)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)"</Require-Capability>
|
||||
<Require-Capability>osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.websocket.api.extensions.Extension)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional</Require-Capability>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -82,7 +82,7 @@
|
|||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
|
||||
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.websocket.api.extensions.Extension</Provide-Capability>
|
||||
<_nouses>true</_nouses>
|
||||
</instructions>
|
||||
|
|
|
@ -66,7 +66,7 @@ public class WebSocketExtensionFactory extends ExtensionFactory
|
|||
}
|
||||
return ext;
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new WebSocketException("Cannot instantiate extension: " + extClass,e);
|
||||
}
|
||||
|
|
|
@ -28,8 +28,8 @@
|
|||
</goals>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
|
||||
<Provide-Capability>osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.websocket.servlet.WebSocketServletFactory</Provide-Capability>
|
||||
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
|
||||
<Provide-Capability>osgi.serviceloader; osgi.serviceloader=javax.servlet.ServletContainerInitializer</Provide-Capability>
|
||||
<_nouses>true</_nouses>
|
||||
</instructions>
|
||||
</configuration>
|
||||
|
|
|
@ -157,9 +157,9 @@ public class NativeWebSocketConfiguration extends ContainerLifeCycle implements
|
|||
{
|
||||
try
|
||||
{
|
||||
return endpointClass.newInstance();
|
||||
return endpointClass.getDeclaredConstructor().newInstance();
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new WebSocketException("Unable to create instance of " + endpointClass.getName(), e);
|
||||
}
|
||||
|
|
|
@ -294,7 +294,7 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
{
|
||||
return objectFactory.createInstance(firstClass);
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new WebSocketException("Unable to create instance of " + firstClass, e);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,6 @@
|
|||
<Bundle-Classpath />
|
||||
<_nouses>true</_nouses>
|
||||
<DynamicImport-Package>org.eclipse.jetty.websocket.server.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}",org.eclipse.jetty.websocket.server.pathmap.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}"</DynamicImport-Package>
|
||||
<Require-Capability>osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.websocket.servlet.WebSocketServletFactory)";cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)"</Require-Capability>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
|
|
@ -329,7 +329,7 @@ public class HttpInputIntegrationTest
|
|||
{
|
||||
System.err.printf("[%d] TEST c=%s, m=%s, delayDispatch=%b delayInFrame=%s content-length:%d expect=%d read=%d content:%s%n",_id,_client.getSimpleName(),_mode,__config.isDelayDispatchUntilContent(),_delay,_length,_status,_read,_send);
|
||||
|
||||
TestClient client=_client.newInstance();
|
||||
TestClient client=_client.getDeclaredConstructor().newInstance();
|
||||
String response = client.send("/ctx/test?mode="+_mode,50,_delay,_length,_send);
|
||||
|
||||
int sum=0;
|
||||
|
@ -368,7 +368,7 @@ public class HttpInputIntegrationTest
|
|||
{
|
||||
try
|
||||
{
|
||||
TestClient client=_client.newInstance();
|
||||
TestClient client=_client.getDeclaredConstructor().newInstance();
|
||||
for (int j=0;j<loops;j++)
|
||||
{
|
||||
String response = client.send("/ctx/test?mode="+_mode,10,_delay,_length,_send);
|
||||
|
|
|
@ -170,7 +170,7 @@ public class DataSourceLoginServiceTest
|
|||
|
||||
protected void changePassword (String user, String newpwd) throws Exception
|
||||
{
|
||||
Loader.loadClass("org.apache.derby.jdbc.EmbeddedDriver").newInstance();
|
||||
Loader.loadClass("org.apache.derby.jdbc.EmbeddedDriver").getDeclaredConstructor().newInstance();
|
||||
try (Connection connection = DriverManager.getConnection(DatabaseLoginServiceTestServer.__dbURL, "", "");
|
||||
Statement stmt = connection.createStatement())
|
||||
{
|
||||
|
|
|
@ -92,7 +92,7 @@ public class DatabaseLoginServiceTestServer
|
|||
//System.err.println("Running script:"+scriptFile.getAbsolutePath());
|
||||
try (FileInputStream fileStream = new FileInputStream(scriptFile))
|
||||
{
|
||||
Loader.loadClass("org.apache.derby.jdbc.EmbeddedDriver").newInstance();
|
||||
Loader.loadClass("org.apache.derby.jdbc.EmbeddedDriver").getDeclaredConstructor().newInstance();
|
||||
Connection connection = DriverManager.getConnection(__dbURL, "", "");
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
return ij.runScript(connection, fileStream, "UTF-8", out, "UTF-8");
|
||||
|
|
|
@ -158,5 +158,47 @@
|
|||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>jdk11</id>
|
||||
<activation>
|
||||
<jdk>11</jdk>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>**/ClusteredSessionScavengingTest</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<!-- if you want to run test even with jdk10/11 -->
|
||||
<profile>
|
||||
<id>alltests</id>
|
||||
<activation>
|
||||
<property>
|
||||
<name>alltests</name>
|
||||
<value>true</value>
|
||||
</property>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<excludes>
|
||||
<exclude>FOOBAR</exclude>
|
||||
</excludes>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
|
|
@ -295,7 +295,8 @@ public class Dump extends HttpServlet
|
|||
{
|
||||
try
|
||||
{
|
||||
throw (Throwable) Thread.currentThread().getContextClassLoader().loadClass(info.substring(1)).newInstance();
|
||||
throw (Throwable) Thread.currentThread().getContextClassLoader()
|
||||
.loadClass(info.substring(1)).getDeclaredConstructor().newInstance();
|
||||
}
|
||||
catch (Throwable th)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue