Merge branch 'master' into javawebsocket-jsr

This commit is contained in:
Joakim Erdfelt 2013-03-18 13:32:08 -07:00
commit 8ec9ac4d64
52 changed files with 2479 additions and 372 deletions

View File

@ -39,6 +39,74 @@ jetty-9.0.0.v20130308 - 08 March 2013
+ 402757 WebSocket client module can't be used with WebSocket server
module in the same WAR
jetty-8.1.10.v20130312 - 12 March 2013
+ 376273 Early EOF because of SSL Protocol Error on
https://api-3t.paypal.com/nvp.
+ 381521 allow compress methods to be configured
+ 392129 fixed handling of timeouts after startAsync
+ 394064 ensure that JarFile instances are closed on JarFileResource.release()
+ 398649 ServletContextListener.contextDestroyed() is not called on
ContextHandler unregistration
+ 399703 made encoding error handling consistent
+ 399799 do not hold lock while calling invalidation listeners
+ 399967 Shutdown hook calls destroy
+ 400040 NullPointerException in HttpGenerator.prepareBuffers
+ 400142 ConcurrentModificationException in JDBC SessionManger
+ 400144 When loading a session fails the JDBCSessionManger produces duplicate
session IDs
+ 400312 ServletContextListener.contextInitialized() is not called when added
in ServletContainerInitializer.onStartup
+ 400457 Thread context classloader hierarchy not searched when finding
webapp's java:comp/env
+ 400859 limit max size of writes from cached content
+ 401211 Remove requirement for jetty-websocket.jar in WEB-INF/lib
+ 401317 Make Safari 5.x websocket support minVersion level error more clear
+ 401382 Prevent parseAvailable from parsing next chunk when previous has not
been consumed. Handle no content-type in chunked request.
+ 401474 Performance problem in org.eclipse.jetty.annotation.AnnotationParser
+ 401485 zip file closed exception
+ 401531 StringIndexOutOfBoundsException for "/*" <url-pattern> of
<jsp-property-group> fix for multiple mappings to *.jsp
+ 401908 Enhance DosFilter to allow dynamic configuration of attributes.
+ 402048 org.eclipse.jetty.server.ShutdownMonitor doesn't stop after the jetty
server is stopped
+ 402485 reseed secure random
+ 402735 jetty.sh to support status which is == check
+ 402833 Test harness for global error page and hide exception message from
reason string
jetty-7.6.10.v20130312 - 12 March 2013
+ 376273 Early EOF because of SSL Protocol Error on
https://api-3t.paypal.com/nvp.
+ 381521 allow compress methods to be configured
+ 394064 ensure that JarFile instances are closed on JarFileResource.release()
+ 398649 ServletContextListener.contextDestroyed() is not called on
ContextHandler unregistration
+ 399703 made encoding error handling consistent
+ 399799 do not hold lock while calling invalidation listeners
+ 399967 Shutdown hook calls destroy
+ 400040 NullPointerException in HttpGenerator.prepareBuffers
+ 400142 ConcurrentModificationException in JDBC SessionManger
+ 400144 When loading a session fails the JDBCSessionManger produces duplicate
session IDs
+ 400457 Thread context classloader hierarchy not searched when finding
webapp's java:comp/env
+ 400859 limit max size of writes from cached content
+ 401211 Remove requirement for jetty-websocket.jar in WEB-INF/lib
+ 401317 Make Safari 5.x websocket support minVersion level error more clear
+ 401382 Prevent parseAvailable from parsing next chunk when previous has not
been consumed. Handle no content-type in chunked request.
+ 401474 Performance problem in org.eclipse.jetty.annotation.AnnotationParser
+ 401531 StringIndexOutOfBoundsException for "/*" <url-pattern> of
<jsp-property-group> fix for multiple mappings to *.jsp
+ 401908 Enhance DosFilter to allow dynamic configuration of attributes.
+ 402048 org.eclipse.jetty.server.ShutdownMonitor doesn't stop after the jetty
server is stopped
+ 402485 reseed secure random
+ 402735 jetty.sh to support status which is == check
+ 402833 Test harness for global error page and hide exception message from
reason string
jetty-9.0.0.RC2 - 24 February 2013
+ Fix etc/jetty.xml TimerScheduler typo that is preventing normal startup
+ Fix etc/jetty-https.xml ExcludeCipherSuites typo that prevents SSL startup

View File

@ -25,6 +25,7 @@ import org.eclipse.jetty.deploy.providers.WebAppProvider;
import org.eclipse.jetty.jmx.MBeanContainer;
import org.eclipse.jetty.security.HashLoginService;
import org.eclipse.jetty.server.ForwardedRequestCustomizer;
import org.eclipse.jetty.server.AsyncNCSARequestLog;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpConnectionFactory;
@ -152,7 +153,8 @@ public class SpdyServer
login.setConfig(jetty_home + "/etc/realm.properties");
server.addBean(login);
NCSARequestLog requestLog = new NCSARequestLog(jetty_home + "/logs/jetty-yyyy_mm_dd.log");
NCSARequestLog requestLog = new AsyncNCSARequestLog();
requestLog.setFilename(jetty_home + "/logs/jetty-yyyy_mm_dd.log");
requestLog.setExtended(false);
requestLogHandler.setRequestLog(requestLog);

View File

@ -62,6 +62,7 @@ public class HostnameVerificationTest
sslContextFactory.setKeyStorePath("src/test/resources/keystore.jks");
sslContextFactory.setKeyStorePassword("storepwd");
}
sslContextFactory.setEndpointIdentificationAlgorithm("HTTPS");
if (server == null)
server = new Server();

View File

@ -10,7 +10,7 @@
<packaging>pom</packaging>
<properties>
<assembly-directory>target/distribution</assembly-directory>
<jetty-setuid-version>1.0.0</jetty-setuid-version>
<jetty-setuid-version>1.0.1</jetty-setuid-version>
</properties>
<build>
<plugins>
@ -161,6 +161,8 @@
<outputDirectory>${assembly-directory}/lib/setuid</outputDirectory>
<destFileName>libsetuid-linux.so</destFileName>
</artifactItem>
<!-- TODO readd once new version released
<artifactItem>
<groupId>org.eclipse.jetty.toolchain.setuid</groupId>
<artifactId>libsetuid-osx</artifactId>
@ -170,6 +172,7 @@
<outputDirectory>${assembly-directory}/lib/setuid</outputDirectory>
<destFileName>libsetuid-osx.so</destFileName>
</artifactItem>
-->
</artifactItems>
</configuration>
</execution>

View File

@ -106,10 +106,28 @@ findDirectory()
running()
{
local PID=$(cat "$1" 2>/dev/null) || return 1
local PID=$(head -n 1 "$1" 2>/dev/null) || return 1
kill -0 "$PID" 2>/dev/null
}
started()
{
# wait for 60s to see "STARTED" in PID file, needs jetty-started.xml as argument
for T in 1 2 3 4 5 6 7 9 10 11 12 13 14 15
do
sleep 4
[ -z "$(grep STARTED $1)" ] || return 0
[ -z "$(grep STOPPED $1)" ] || return 1
[ -z "$(grep FAILED $1)" ] || return 1
local PID=$(head -n 1 "$1" 2>/dev/null) || return 1
kill -0 "$PID" 2>/dev/null || return 1
echo -n ". "
done
return 1;
}
readConfig()
{
(( DEBUG )) && echo "Reading $1.."
@ -137,7 +155,13 @@ shift
##################################################
# Read any configuration files
##################################################
for CONFIG in /etc/default/jetty{,9} $HOME/.jettyrc; do
ETC=/etc
if [ $UID != 0 ]
then
ETC=$HOME/etc
fi
for CONFIG in $ETC/default/jetty{,9} $HOME/.jettyrc; do
if [ -f "$CONFIG" ] ; then
readConfig "$CONFIG"
fi
@ -262,9 +286,9 @@ fi
##################################################
if [ -z "$JETTY_CONF" ]
then
if [ -f /etc/jetty.conf ]
if [ -f $ETC/jetty.conf ]
then
JETTY_CONF=/etc/jetty.conf
JETTY_CONF=$ETC/jetty.conf
elif [ -f "$JETTY_HOME/etc/jetty.conf" ]
then
JETTY_CONF=$JETTY_HOME/etc/jetty.conf
@ -318,6 +342,7 @@ if [ -z "$JETTY_PID" ]
then
JETTY_PID="$JETTY_RUN/jetty.pid"
fi
JAVA_OPTIONS+=("-Djetty.pid=$JETTY_PID")
##################################################
# Setup JAVA if unset
@ -407,23 +432,15 @@ case "$ACTION" in
exit
fi
if type start-stop-daemon > /dev/null 2>&1
if [ $UID -eq 0 ] && type start-stop-daemon > /dev/null 2>&1
then
unset CH_USER
if [ -n "$JETTY_USER" ]
then
CH_USER="-c$JETTY_USER"
fi
if start-stop-daemon -S -p"$JETTY_PID" $CH_USER -d"$JETTY_HOME" -b -m -a "$JAVA" -- "${RUN_ARGS[@]}" --daemon
then
sleep 1
if running "$JETTY_PID"
then
echo "OK"
else
echo "FAILED"
fi
fi
start-stop-daemon -S -p"$JETTY_PID" $CH_USER -d"$JETTY_HOME" -b -m -a "$JAVA" -- "${RUN_ARGS[@]}" --daemon
else
@ -454,14 +471,21 @@ case "$ACTION" in
echo $! > "$JETTY_PID"
fi
echo "STARTED Jetty `date`"
fi
if started "$JETTY_PID"
then
echo "OK `date`"
else
echo "FAILED `date`"
exit 1
fi
;;
stop)
echo -n "Stopping Jetty: "
if type start-stop-daemon > /dev/null 2>&1; then
if [ $UID -eq 0 ] && type start-stop-daemon > /dev/null 2>&1; then
start-stop-daemon -K -p"$JETTY_PID" -d"$JETTY_HOME" -a "$JAVA" -s HUP
TIMEOUT=30
@ -476,7 +500,7 @@ case "$ACTION" in
rm -f "$JETTY_PID"
echo OK
else
PID=$(cat "$JETTY_PID" 2>/dev/null)
PID=$(head -n 1 "$JETTY_PID" 2>/dev/null)
kill "$PID" 2>/dev/null
TIMEOUT=30
@ -537,7 +561,7 @@ case "$ACTION" in
;;
check)
check|status)
echo "Checking arguments to Jetty: "
echo "JETTY_HOME = $JETTY_HOME"
echo "JETTY_CONF = $JETTY_CONF"

View File

@ -0,0 +1,15 @@
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure_9_0.dtd">
<!-- =============================================================== -->
<!-- Mixin the Start FileNoticeLifeCycleListener -->
<!-- =============================================================== -->
<Configure id="Server" class="org.eclipse.jetty.server.Server">
<Call name="addLifeCycleListener">
<Arg>
<New class="org.eclipse.jetty.util.component.FileNoticeLifeCycleListener">
<Arg><SystemProperty name="jetty.pid" default="./jetty.pid"/></Arg>
</New>
</Arg>
</Call>
</Configure>

View File

@ -6,8 +6,7 @@
# created by that script.
#
# Each line in this file becomes an arguement to start.jar
# unless this file contains an --ini option, then these
# arguments will be in addition to those found in the
# start.ini file
# in addition to those found in the start.ini file
# =======================================================
--pre=etc/jetty-logging.xml
etc/jetty-logging.xml
etc/jetty-started.xml

View File

@ -83,17 +83,6 @@
# -XX:CMSInitiatingOccupancyFraction=80
#===========================================================
#===========================================================
# Enable SetUID
# To enable setuid you must have the jetty-setuid.xml as the
# first xml file to be processed.
# The default user and group is 'jetty' and if you are
# starting as root you must change the run privledged to true
#-----------------------------------------------------------
# OPTIONS=setuid
# etc/jetty-setuid.xml
#===========================================================
#===========================================================
# Default Server Options
# Use the core server jars with websocket on the classpath
@ -107,6 +96,19 @@ etc/jetty.xml
start.d/
#===========================================================
#===========================================================
# Enable SetUID
# The default user and group is 'jetty' and if you are
# starting as root you must change the run privledged to true
#-----------------------------------------------------------
# OPTIONS=setuid
# etc/jetty-setuid.xml
# jetty.startServerAsPrivileged=false
# jetty.username=jetty
# jetty.groupname=jetty
# jetty.umask=002
#===========================================================
#===========================================================
# Server logging.
# The following configuration will redirect stderr and stdout

View File

@ -112,16 +112,14 @@ public interface HttpContent
@Override
public ByteBuffer getIndirectBuffer()
{
try
if (_resource.length()<=0 || _maxBuffer<_resource.length())
return null;
int length=(int)_resource.length();
byte[] array = new byte[length];
int offset=0;
try (InputStream in=_resource.getInputStream())
{
if (_resource.length()<=0 || _maxBuffer<_resource.length())
return null;
int length=(int)_resource.length();
byte[] array = new byte[length];
int offset=0;
InputStream in=_resource.getInputStream();
do
{
int filled=in.read(array,offset,length);

View File

@ -26,16 +26,13 @@ import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.thread.Scheduler;
/* ------------------------------------------------------------ */
/** An Abstract implementation of an Idle Timeout.
*
/**
* An Abstract implementation of an Idle Timeout.
* <p/>
* This implementation is optimised that timeout operations are not cancelled on
* every operation. Rather timeout are allowed to expire and a check is then made
* to see when the last operation took place. If the idle timeout has not expired,
* the timeout is rescheduled for the earliest possible time a timeout could occur.
*
*/
public abstract class IdleTimeout
{
@ -43,15 +40,15 @@ public abstract class IdleTimeout
private final Scheduler _scheduler;
private final AtomicReference<Scheduler.Task> _timeout = new AtomicReference<>();
private volatile long _idleTimeout;
private volatile long _idleTimestamp=System.currentTimeMillis();
private volatile long _idleTimestamp = System.currentTimeMillis();
private final Runnable _idleTask = new Runnable()
{
@Override
public void run()
{
long idleLeft=checkIdleTimeout();
if (idleLeft>=0)
long idleLeft = checkIdleTimeout();
if (idleLeft >= 0)
scheduleIdleTimeout(idleLeft > 0 ? idleLeft : getIdleTimeout());
}
};
@ -61,7 +58,7 @@ public abstract class IdleTimeout
*/
public IdleTimeout(Scheduler scheduler)
{
_scheduler=scheduler;
_scheduler = scheduler;
}
public long getIdleTimestamp()
@ -76,14 +73,14 @@ public abstract class IdleTimeout
public void setIdleTimeout(long idleTimeout)
{
long old=_idleTimeout;
long old = _idleTimeout;
_idleTimeout = idleTimeout;
// Do we have an old timeout
if (old>0)
if (old > 0)
{
// if the old was less than or equal to the new timeout, then nothing more to do
if (old<=idleTimeout)
if (old <= idleTimeout)
return;
// old timeout is too long, so cancel it.
@ -93,22 +90,22 @@ public abstract class IdleTimeout
}
// If we have a new timeout, then check and reschedule
if (idleTimeout>0 && isOpen())
if (idleTimeout > 0 && isOpen())
_idleTask.run();
}
/** This method should be called when non-idle activity has taken place.
/**
* This method should be called when non-idle activity has taken place.
*/
public void notIdle()
{
_idleTimestamp=System.currentTimeMillis();
_idleTimestamp = System.currentTimeMillis();
}
private void scheduleIdleTimeout(long delay)
{
Scheduler.Task newTimeout = null;
if (isOpen() && delay > 0 && _scheduler!=null)
if (isOpen() && delay > 0 && _scheduler != null)
newTimeout = _scheduler.schedule(_idleTask, delay, TimeUnit.MILLISECONDS);
Scheduler.Task oldTimeout = _timeout.getAndSet(newTimeout);
if (oldTimeout != null)
@ -117,10 +114,10 @@ public abstract class IdleTimeout
public void onOpen()
{
if (_idleTimeout>0)
if (_idleTimeout > 0)
_idleTask.run();
}
public void onClose()
{
Scheduler.Task oldTimeout = _timeout.getAndSet(null);
@ -162,22 +159,23 @@ public abstract class IdleTimeout
}
}
return idleLeft>=0?idleLeft:0;
return idleLeft >= 0 ? idleLeft : 0;
}
return -1;
}
/* ------------------------------------------------------------ */
/** This abstract method is called when the idle timeout has expired.
/**
* This abstract method is called when the idle timeout has expired.
*
* @param timeout a TimeoutException
*/
abstract protected void onIdleExpired(TimeoutException timeout);
protected abstract void onIdleExpired(TimeoutException timeout);
/* ------------------------------------------------------------ */
/** This abstract method should be called to check if idle timeouts
/**
* This abstract method should be called to check if idle timeouts
* should still be checked.
*
* @return True if the entity monitored should still be checked for idle timeouts
*/
abstract protected boolean isOpen();
public abstract boolean isOpen();
}

View File

@ -41,6 +41,7 @@ import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.jetty.util.ConcurrentArrayQueue;
import org.eclipse.jetty.util.TypeUtil;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.component.ContainerLifeCycle;
@ -93,7 +94,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
/**
* Get the connect timeout
*
*
* @return the connect timeout (in milliseconds)
*/
public long getConnectTimeout()
@ -103,7 +104,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
/**
* Set the connect timeout (in milliseconds)
*
*
* @param milliseconds the number of milliseconds for the timeout
*/
public void setConnectTimeout(long milliseconds)
@ -317,7 +318,8 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
*/
public class ManagedSelector extends AbstractLifeCycle implements Runnable, Dumpable
{
private final Queue<Runnable> _changes = new ConcurrentLinkedQueue<>();
private final Queue<Runnable> _changes = new ConcurrentArrayQueue<>();
private final int _id;
private Selector _selector;
private volatile Thread _thread;
@ -364,7 +366,7 @@ public abstract class SelectorManager extends AbstractLifeCycle implements Dumpa
if (_runningChanges)
_changes.offer(change);
else
{
{
// Otherwise we run the queued changes
runChanges();
// and then directly run the passed change

View File

@ -24,7 +24,6 @@ import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.util.Arrays;
import java.util.concurrent.Executor;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
@ -67,8 +66,8 @@ import org.eclipse.jetty.util.log.Logger;
* encrypted endpoint, but if insufficient bytes are read it will NOT call {@link EndPoint#fillInterested(Callback)}.
* <p>
* It is only the active methods : {@link DecryptedEndPoint#fillInterested(Callback)} and
* {@link DecryptedEndPoint#write(Object, Callback, ByteBuffer...)} that may schedule callbacks by calling the encrypted
* {@link EndPoint#fillInterested(Callback)} and {@link EndPoint#write(Object, Callback, ByteBuffer...)}
* {@link DecryptedEndPoint#write(Callback, ByteBuffer...)} that may schedule callbacks by calling the encrypted
* {@link EndPoint#fillInterested(Callback)} and {@link EndPoint#write(Callback, ByteBuffer...)}
* methods. For normal data handling, the decrypted fillInterest method will result in an encrypted fillInterest and a decrypted
* write will result in an encrypted write. However, due to SSL handshaking requirements, it is also possible for a decrypted fill
* to call the encrypted write and for the decrypted flush to call the encrypted fillInterested methods.
@ -114,7 +113,7 @@ public class SslConnection extends AbstractConnection
{
try
{
((SocketBased) endPoint).getSocket().setSoLinger(true,30000);
((SocketBased)endPoint).getSocket().setSoLinger(true, 30000);
}
catch (SocketException e)
{
@ -162,25 +161,12 @@ public class SslConnection extends AbstractConnection
super.onClose();
}
// @Override
// public int getMessagesIn()
// {
// return _decryptedEndPoint.getConnection().getMessagesIn();
// }
//
// @Override
// public int getMessagesOut()
// {
// return _decryptedEndPoint.getConnection().getMessagesOut();
// }
@Override
public void close()
{
getDecryptedEndPoint().getConnection().close();
}
/* ------------------------------------------------------------ */
@Override
public void onFillable()
{
@ -211,7 +197,6 @@ public class SslConnection extends AbstractConnection
LOG.debug("onFillable exit {}", getEndPoint());
}
/* ------------------------------------------------------------ */
@Override
public void onFillInterestedFailed(Throwable cause)
{
@ -220,19 +205,21 @@ public class SslConnection extends AbstractConnection
// the decrypted readInterest and/or writeFlusher so that they will attempt
// to do the fill and/or flush again and these calls will do the actually
// handle the cause.
_decryptedEndPoint.getFillInterest().onFail(cause);
boolean failFlusher = false;
synchronized(_decryptedEndPoint)
{
_decryptedEndPoint.getFillInterest().onFail(cause);
if (_decryptedEndPoint._flushRequiresFillToProgress)
{
_decryptedEndPoint._flushRequiresFillToProgress = false;
_decryptedEndPoint.getWriteFlusher().onFail(cause);
failFlusher = true;
}
}
if (failFlusher)
_decryptedEndPoint.getWriteFlusher().onFail(cause);
}
/* ------------------------------------------------------------ */
@Override
public String toString()
{
@ -250,7 +237,6 @@ public class SslConnection extends AbstractConnection
_decryptedEndPoint.getConnection());
}
/* ------------------------------------------------------------ */
public class DecryptedEndPoint extends AbstractEndPoint
{
private boolean _fillRequiresFlushToProgress;
@ -266,6 +252,7 @@ public class SslConnection extends AbstractConnection
// This means that a write of encrypted data has completed. Writes are done
// only if there is a pending writeflusher or a read needed to write
// data. In either case the appropriate callback is passed on.
boolean fillable = false;
synchronized (DecryptedEndPoint.this)
{
if (DEBUG)
@ -278,11 +265,12 @@ public class SslConnection extends AbstractConnection
if (_fillRequiresFlushToProgress)
{
_fillRequiresFlushToProgress = false;
getFillInterest().fillable();
fillable = true;
}
getExecutor().execute(_runCompletWrite);
}
if (fillable)
getFillInterest().fillable();
getExecutor().execute(_runCompletWrite);
}
@Override
@ -291,12 +279,12 @@ public class SslConnection extends AbstractConnection
// This means that a write of data has failed. Writes are done
// only if there is an active writeflusher or a read needed to write
// data. In either case the appropriate callback is passed on.
boolean failFiller = false;
synchronized (DecryptedEndPoint.this)
{
if (DEBUG)
LOG.debug("{} write.failed", SslConnection.this, x);
if (_encryptedOutput != null)
BufferUtil.clear(_encryptedOutput);
BufferUtil.clear(_encryptedOutput);
releaseEncryptedOutputBuffer();
_cannotAcceptMoreAppDataToFlush = false;
@ -304,11 +292,12 @@ public class SslConnection extends AbstractConnection
if (_fillRequiresFlushToProgress)
{
_fillRequiresFlushToProgress = false;
getFillInterest().onFail(x);
failFiller = true;
}
getWriteFlusher().onFail(x);
}
if (failFiller)
getFillInterest().onFail(x);
getWriteFlusher().onFail(x);
}
};
@ -344,6 +333,7 @@ public class SslConnection extends AbstractConnection
// all data could be wrapped. So either we need to write some encrypted data,
// OR if we are handshaking we need to read some encrypted data OR
// if neither then we should just try the flush again.
boolean flush = false;
synchronized (DecryptedEndPoint.this)
{
if (DEBUG)
@ -355,19 +345,30 @@ public class SslConnection extends AbstractConnection
_cannotAcceptMoreAppDataToFlush = true;
getEndPoint().write(_writeCallback, _encryptedOutput);
}
// If we are handshaking and need to read,
else if (_sslEngine.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP)
{
// we are actually read blocked in order to write
_flushRequiresFillToProgress=true;
// check if we are actually read blocked in order to write
_flushRequiresFillToProgress = true;
SslConnection.this.fillInterested();
}
else if (isOutputShutdown())
{
getWriteFlusher().onClose();
}
else
{
// try the flush again
flush = true;
}
}
if (flush)
{
// If the output is closed,
if (isOutputShutdown())
{
// don't bother writing, just notify of close
getWriteFlusher().onClose();
}
// Else,
else
{
// try to flush what is pending
getWriteFlusher().completeWrite();
}
}
@ -413,9 +414,11 @@ public class SslConnection extends AbstractConnection
}
}
else
{
// Normal readable callback
// Get called back on onfillable when then is more data to fill
SslConnection.this.fillInterested();
}
return false;
}

View File

@ -22,7 +22,6 @@ package org.eclipse.jetty.io;
import java.util.concurrent.TimeoutException;
import junit.framework.Assert;
import org.eclipse.jetty.util.thread.TimerScheduler;
import org.junit.After;
import org.junit.Before;
@ -32,10 +31,10 @@ public class IdleTimeoutTest
{
volatile boolean _open;
volatile TimeoutException _expired;
TimerScheduler _timer;
IdleTimeout _timeout;
@Before
public void setUp() throws Exception
{
@ -50,9 +49,9 @@ public class IdleTimeoutTest
{
_expired=timeout;
}
@Override
protected boolean isOpen()
public boolean isOpen()
{
return _open;
}
@ -65,7 +64,7 @@ public class IdleTimeoutTest
{
_open=false;
_timer.stop();
}
@Test
@ -76,10 +75,10 @@ public class IdleTimeoutTest
Thread.sleep(100);
_timeout.notIdle();
}
Assert.assertNull(_expired);
}
@Test
public void testIdle() throws Exception
{
@ -91,7 +90,7 @@ public class IdleTimeoutTest
Thread.sleep(1500);
Assert.assertNotNull(_expired);
}
@Test
public void testClose() throws Exception
{
@ -104,7 +103,7 @@ public class IdleTimeoutTest
Thread.sleep(1500);
Assert.assertNull(_expired);
}
@Test
public void testClosed() throws Exception
{
@ -153,7 +152,7 @@ public class IdleTimeoutTest
Thread.sleep(1000);
Assert.assertNotNull(_expired);
}
}

View File

@ -1,4 +1,5 @@
<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/maven-v4_0_0.xsd">
<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/maven-v4_0_0.xsd">
<parent>
<groupId>org.eclipse.jetty.osgi</groupId>
<artifactId>jetty-osgi-project</artifactId>
@ -8,24 +9,40 @@
<artifactId>jetty-osgi-npn</artifactId>
<name>Jetty :: OSGi NPN Fragment</name>
<packaging>jar</packaging>
<properties>
<bundle-symbolic-name>org.eclipse.jetty.osgi.npn.fragment</bundle-symbolic-name>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Bundle-ManifestVersion>2</Bundle-ManifestVersion>
<Bundle-SymbolicName>org.eclipse.jetty.osgi.npn.fragment;singleton:=true</Bundle-SymbolicName>
<Bundle-Name>Jetty OSGi NPN Fragment</Bundle-Name>
<Bundle-Version>9.0.0</Bundle-Version>
<Export-Package>org.eclipse.jetty.npn;version="1.1.2"</Export-Package>
<Fragment-Host>system.bundle;extension:=framework</Fragment-Host>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.7</version>
<executions>
<execution>
<id>parse-version</id>
<goals>
<goal>parse-version</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Bundle-ManifestVersion>2</Bundle-ManifestVersion>
<Bundle-SymbolicName>${bundle-symbolic-name};singleton:=true</Bundle-SymbolicName>
<Bundle-Name>Jetty OSGi NPN Fragment</Bundle-Name>
<Bundle-Version>${parsedVersion.osgiVersion}</Bundle-Version>
<Export-Package>org.eclipse.jetty.npn;version="1.1.5"</Export-Package>
<Fragment-Host>system.bundle;extension:=framework</Fragment-Host>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -19,7 +19,7 @@
<felixversion>4.0.3</felixversion>
<injection.bundle.version>1.0</injection.bundle.version>
<runner.version>1.7.6</runner.version>
<npn-version>1.1.2.v20130305</npn-version>
<npn-version>1.1.5.v20130313</npn-version>
</properties>
<dependencies>
<!-- Pax Exam Dependencies -->

View File

@ -17,6 +17,14 @@
<!-- Consult the javadoc of o.e.j.util.ssl.SslContextFactory -->
<!-- o.e.j.server.HttpConnectionFactory for all configuration -->
<!-- that may be set here. -->
<!-- -->
<!-- The keyManagerPassword is passed as the password arg to -->
<!-- KeyManagerFactory.init(...) -->
<!-- If there is no keymanagerpassword, then the -->
<!-- keystorepassword is used instead. -->
<!-- If there is no trustmanager set, then the keystore is used -->
<!-- as the trust store and the keystorepassword is used as the -->
<!-- truststore password. -->
<!-- =========================================================== -->
<New id="sslContextFactory" class="org.eclipse.jetty.util.ssl.SslContextFactory">
<Set name="KeyStorePath"><Property name="jetty.home" default="." />/etc/keystore</Set>
@ -24,6 +32,7 @@
<Set name="KeyManagerPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set>
<Set name="TrustStorePath"><Property name="jetty.home" default="." />/etc/keystore</Set>
<Set name="TrustStorePassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set>
<Set name="EndpointIdentificationAlgorithm"></Set>
<Set name="ExcludeCipherSuites">
<Array type="String">
<Item>SSL_RSA_WITH_DES_CBC_SHA</Item>

View File

@ -14,7 +14,7 @@
<Arg>
<New id="RequestLog" class="org.eclipse.jetty.server.handler.RequestLogHandler">
<Set name="requestLog">
<New id="RequestLogImpl" class="org.eclipse.jetty.server.NCSARequestLog">
<New id="RequestLogImpl" class="org.eclipse.jetty.server.AsyncNCSARequestLog">
<Set name="filename"><Property name="jetty.logs" default="./logs" />/yyyy_mm_dd.request.log</Set>
<Set name="filenameDateFormat">yyyy_MM_dd</Set>
<Set name="retainDays">90</Set>

View File

@ -44,8 +44,14 @@
<!-- =========================================================== -->
<Arg name="threadpool">
<New id="threadpool" class="org.eclipse.jetty.util.thread.QueuedThreadPool">
<Set name="minThreads">10</Set>
<Set name="maxThreads">200</Set>
<Arg name="minThreads">10</Arg>
<Arg name="maxThreads">200</Arg>
<Arg name="idleTimeout">60000</Arg>
<Arg name="queue">
<New class="org.eclipse.jetty.util.ConcurrentArrayBlockingQueue$Unbounded">
<Arg>32</Arg>
</New>
</Arg>
<Set name="detailedDump">false</Set>
</New>
</Arg>

View File

@ -0,0 +1,131 @@
//
// ========================================================================
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.server;
import org.eclipse.jetty.util.BlockingArrayQueue;
import org.eclipse.jetty.util.ConcurrentArrayBlockingQueue;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import java.io.IOException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
/* ------------------------------------------------------------ */
/**
* An asynchronously writing NCSA Request Log
*/
public class AsyncNCSARequestLog extends NCSARequestLog
{
private static final Logger LOG = Log.getLogger(AsyncNCSARequestLog.class);
private final BlockingQueue<String> _queue;
private transient WriterThread _thread;
private boolean _warnedFull;
public AsyncNCSARequestLog()
{
this(null,null);
}
public AsyncNCSARequestLog(BlockingQueue<String> queue)
{
this(null,queue);
}
public AsyncNCSARequestLog(String filename)
{
this(filename,null);
}
public AsyncNCSARequestLog(String filename,BlockingQueue<String> queue)
{
super(filename);
if (queue==null)
queue=new ConcurrentArrayBlockingQueue.Bounded<String>(1024);
_queue=queue;
}
private class WriterThread extends Thread
{
WriterThread()
{
setName("AsyncNCSARequestLog@"+Integer.toString(AsyncNCSARequestLog.this.hashCode(),16));
}
@Override
public void run()
{
while (isRunning())
{
try
{
String log = _queue.poll(10,TimeUnit.SECONDS);
if (log!=null)
AsyncNCSARequestLog.super.write(log);
while(!_queue.isEmpty())
{
log=_queue.poll();
if (log!=null)
AsyncNCSARequestLog.super.write(log);
}
}
catch (IOException e)
{
LOG.warn(e);
}
catch (InterruptedException e)
{
LOG.ignore(e);
}
}
}
}
@Override
protected synchronized void doStart() throws Exception
{
super.doStart();
_thread = new WriterThread();
_thread.start();
}
@Override
protected void doStop() throws Exception
{
_thread.interrupt();
_thread.join();
super.doStop();
_thread=null;
}
@Override
protected void write(String log) throws IOException
{
if (!_queue.offer(log))
{
if (_warnedFull)
LOG.warn("Log Queue overflow");
_warnedFull=true;
}
}
}

View File

@ -55,6 +55,14 @@ import org.eclipse.jetty.util.log.Logger;
public class NCSARequestLog extends AbstractLifeCycle implements RequestLog
{
private static final Logger LOG = Log.getLogger(NCSARequestLog.class);
private static ThreadLocal<StringBuilder> _buffers = new ThreadLocal<StringBuilder>()
{
@Override
protected StringBuilder initialValue()
{
return new StringBuilder(256);
}
};
private String _filename;
private boolean _extended;
@ -468,7 +476,8 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog
if (_fileOut == null)
return;
StringBuilder buf= new StringBuilder(256);
StringBuilder buf= _buffers.get();
buf.setLength(0);
if (_logServer)
{
@ -584,22 +593,29 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog
}
buf.append(StringUtil.__LINE_SEPARATOR);
String log = buf.toString();
synchronized(this)
{
if (_writer==null)
return;
_writer.write(log);
_writer.flush();
}
write(log);
}
catch (IOException e)
{
LOG.warn(e);
}
}
/* ------------------------------------------------------------ */
protected void write(String log) throws IOException
{
synchronized(this)
{
if (_writer==null)
return;
_writer.write(log);
_writer.flush();
}
}
/* ------------------------------------------------------------ */
/**
* Writes extended request and response information to the output stream.
@ -669,7 +685,10 @@ public class NCSARequestLog extends AbstractLifeCycle implements RequestLog
else
_ignorePathMap = null;
_writer = new OutputStreamWriter(_out);
synchronized(this)
{
_writer = new OutputStreamWriter(_out);
}
super.doStart();
}

View File

@ -280,10 +280,12 @@ public class Server extends HandlerWrapper implements Attributes
@Override
protected void doStart() throws Exception
{
if (getStopAtShutdown()) {
ShutdownThread.register(this);
ShutdownMonitor.getInstance().start(); // initialize
if (getStopAtShutdown())
{
ShutdownThread.register(this);
}
ShutdownMonitor.getInstance().start(); // initialize
LOG.info("jetty-"+getVersion());
HttpGenerator.setServerVersion(getVersion());

View File

@ -40,7 +40,7 @@ import org.eclipse.jetty.util.thread.ShutdownThread;
* <p>
* Commands "stop" and "status" are currently supported.
*/
public class ShutdownMonitor extends Thread
public class ShutdownMonitor
{
// Implementation of safe lazy init, using Initialization on Demand Holder technique.
static class Holder
@ -53,11 +53,164 @@ public class ShutdownMonitor extends Thread
return Holder.instance;
}
/**
* ShutdownMonitorThread
*
* Thread for listening to STOP.PORT for command to stop Jetty.
* If ShowndownMonitor.exitVm is true, then Sytem.exit will also be
* called after the stop.
*
*/
public class ShutdownMonitorThread extends Thread
{
public ShutdownMonitorThread ()
{
setDaemon(true);
setName("ShutdownMonitor");
}
@Override
public void run()
{
if (serverSocket == null)
{
return;
}
while (serverSocket != null)
{
Socket socket = null;
try
{
socket = serverSocket.accept();
LineNumberReader lin = new LineNumberReader(new InputStreamReader(socket.getInputStream()));
String receivedKey = lin.readLine();
if (!key.equals(receivedKey))
{
System.err.println("Ignoring command with incorrect key");
continue;
}
OutputStream out = socket.getOutputStream();
String cmd = lin.readLine();
debug("command=%s",cmd);
if ("stop".equals(cmd))
{
// Graceful Shutdown
debug("Issuing graceful shutdown..");
ShutdownThread.getInstance().run();
// Reply to client
debug("Informing client that we are stopped.");
out.write("Stopped\r\n".getBytes(StringUtil.__UTF8));
out.flush();
// Shutdown Monitor
debug("Shutting down monitor");
close(socket);
socket = null;
close(serverSocket);
serverSocket = null;
if (exitVm)
{
// Kill JVM
debug("Killing JVM");
System.exit(0);
}
}
else if ("status".equals(cmd))
{
// Reply to client
out.write("OK\r\n".getBytes(StringUtil.__UTF8));
out.flush();
}
}
catch (Exception e)
{
debug(e);
System.err.println(e.toString());
}
finally
{
close(socket);
socket = null;
}
}
}
public void start()
{
if (isAlive())
{
System.err.printf("ShutdownMonitorThread already started");
return; // cannot start it again
}
startListenSocket();
if (serverSocket == null)
{
return;
}
System.err.println("Starting ShutdownMonitorThread");
super.start();
}
private void startListenSocket()
{
if (port < 0)
{
if (DEBUG)
System.err.println("ShutdownMonitor not in use (port < 0): " + port);
return;
}
try
{
serverSocket = new ServerSocket(port,1,InetAddress.getByName("127.0.0.1"));
if (port == 0)
{
// server assigned port in use
port = serverSocket.getLocalPort();
System.out.printf("STOP.PORT=%d%n",port);
}
if (key == null)
{
// create random key
key = Long.toString((long)(Long.MAX_VALUE * Math.random() + this.hashCode() + System.currentTimeMillis()),36);
System.out.printf("STOP.KEY=%s%n",key);
}
}
catch (Exception e)
{
debug(e);
System.err.println("Error binding monitor port " + port + ": " + e.toString());
serverSocket = null;
}
finally
{
// establish the port and key that are in use
debug("STOP.PORT=%d",port);
debug("STOP.KEY=%s",key);
debug("%s",serverSocket);
}
}
}
private boolean DEBUG;
private int port;
private String key;
private boolean exitVm;
private ServerSocket serverSocket;
private ShutdownMonitorThread thread;
/**
* Create a ShutdownMonitor using configuration from the System properties.
@ -75,7 +228,7 @@ public class ShutdownMonitor extends Thread
// Use values passed thru via /jetty-start/
this.port = Integer.parseInt(props.getProperty("STOP.PORT","-1"));
this.key = props.getProperty("STOP.KEY","eclipse");
this.key = props.getProperty("STOP.KEY",null);
this.exitVm = true;
}
@ -149,77 +302,6 @@ public class ShutdownMonitor extends Thread
return exitVm;
}
@Override
public void run()
{
if (serverSocket == null)
{
return;
}
while (serverSocket != null)
{
Socket socket = null;
try
{
socket = serverSocket.accept();
LineNumberReader lin = new LineNumberReader(new InputStreamReader(socket.getInputStream()));
String key = lin.readLine();
if (!this.key.equals(key))
{
System.err.println("Ignoring command with incorrect key");
continue;
}
OutputStream out = socket.getOutputStream();
String cmd = lin.readLine();
debug("command=%s",cmd);
if ("stop".equals(cmd))
{
// Graceful Shutdown
debug("Issuing graceful shutdown..");
ShutdownThread.getInstance().run();
// Reply to client
debug("Informing client that we are stopped.");
out.write("Stopped\r\n".getBytes(StringUtil.__UTF8));
out.flush();
// Shutdown Monitor
debug("Shutting down monitor");
close(socket);
socket = null;
close(serverSocket);
serverSocket = null;
if (exitVm)
{
// Kill JVM
debug("Killing JVM");
System.exit(0);
}
}
else if ("status".equals(cmd))
{
// Reply to client
out.write("OK\r\n".getBytes(StringUtil.__UTF8));
out.flush();
}
}
catch (Exception e)
{
debug(e);
System.err.println(e.toString());
}
finally
{
close(socket);
socket = null;
}
}
}
public void setDebug(boolean flag)
{
@ -228,90 +310,71 @@ public class ShutdownMonitor extends Thread
public void setExitVm(boolean exitVm)
{
if (isAlive())
synchronized (this)
{
throw new IllegalStateException("ShutdownMonitor already started");
if (thread != null && thread.isAlive())
{
throw new IllegalStateException("ShutdownMonitorThread already started");
}
this.exitVm = exitVm;
}
this.exitVm = exitVm;
}
public void setKey(String key)
{
if (isAlive())
synchronized (this)
{
throw new IllegalStateException("ShutdownMonitor already started");
if (thread != null && thread.isAlive())
{
throw new IllegalStateException("ShutdownMonitorThread already started");
}
this.key = key;
}
this.key = key;
}
public void setPort(int port)
{
if (isAlive())
synchronized (this)
{
throw new IllegalStateException("ShutdownMonitor already started");
}
this.port = port;
}
public void start()
{
if (isAlive())
{
System.err.printf("ShutdownMonitor already started");
return; // cannot start it again
}
startListenSocket();
if (serverSocket == null)
{
return;
}
super.start();
}
private void startListenSocket()
{
if (this.port < 0)
{
if (DEBUG)
System.err.println("ShutdownMonitor not in use (port < 0): " + port);
return;
}
try
{
setDaemon(true);
setName("ShutdownMonitor");
this.serverSocket = new ServerSocket(this.port,1,InetAddress.getByName("127.0.0.1"));
if (this.port == 0)
if (thread != null && thread.isAlive())
{
// server assigned port in use
this.port = serverSocket.getLocalPort();
System.out.printf("STOP.PORT=%d%n",this.port);
throw new IllegalStateException("ShutdownMonitorThread already started");
}
if (this.key == null)
{
// create random key
this.key = Long.toString((long)(Long.MAX_VALUE * Math.random() + this.hashCode() + System.currentTimeMillis()),36);
System.out.printf("STOP.KEY=%s%n",this.key);
}
}
catch (Exception e)
{
debug(e);
System.err.println("Error binding monitor port " + this.port + ": " + e.toString());
}
finally
{
// establish the port and key that are in use
debug("STOP.PORT=%d",this.port);
debug("STOP.KEY=%s",this.key);
debug("%s",serverSocket);
this.port = port;
}
}
protected void start() throws Exception
{
ShutdownMonitorThread t = null;
synchronized (this)
{
if (thread != null && thread.isAlive())
{
System.err.printf("ShutdownMonitorThread already started");
return; // cannot start it again
}
thread = new ShutdownMonitorThread();
t = thread;
}
if (t != null)
t.start();
}
protected boolean isAlive ()
{
boolean result = false;
synchronized (this)
{
result = (thread != null && thread.isAlive());
}
return result;
}
@Override
public String toString()
{

View File

@ -18,7 +18,7 @@
package org.eclipse.jetty.server;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.*;
import java.io.IOException;
import java.io.InputStream;
@ -39,6 +39,7 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
import org.eclipse.jetty.toolchain.test.annotation.Stress;
import org.eclipse.jetty.toolchain.test.PropertyFlag;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -95,7 +96,14 @@ public class AsyncStressTest
@Stress("High connection count")
public void testAsync() throws Throwable
{
doConnections(1600,240);
if (PropertyFlag.isEnabled("test.stress"))
{
doConnections(1600,240);
}
else
{
doConnections(80,80);
}
}
private void doConnections(int connections,final int loops) throws Throwable

View File

@ -49,8 +49,13 @@ public class HttpManyWaysToAsyncCommitTest extends AbstractHttpTest
@Parameterized.Parameters
public static Collection<Object[]> data()
{
Object[][] data = new Object[][]{{HttpVersion.HTTP_1_0.asString(), true}, {HttpVersion.HTTP_1_0.asString(),
false}, {HttpVersion.HTTP_1_1.asString(), true}, {HttpVersion.HTTP_1_1.asString(), false}};
Object[][] data = new Object[][]
{
{HttpVersion.HTTP_1_0.asString(), true},
{HttpVersion.HTTP_1_1.asString(), true},
{HttpVersion.HTTP_1_0.asString(), false},
{HttpVersion.HTTP_1_1.asString(), false}
};
return Arrays.asList(data);
}

View File

@ -35,6 +35,7 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.toolchain.test.PropertyFlag;
import org.eclipse.jetty.util.IO;
import org.junit.After;
import org.junit.Before;
@ -42,7 +43,7 @@ import org.junit.Before;
public class HttpServerTestFixture
{ // Useful constants
protected static final long PAUSE=10L;
protected static final int LOOPS=50;
protected static final int LOOPS=PropertyFlag.isEnabled("test.stress")?250:50;
protected Server _server;
protected URI _serverURI;

View File

@ -0,0 +1,112 @@
//
// ========================================================================
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.server;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import org.junit.Test;
/**
* ShutdownMonitorTest
*
*
*
*/
public class ShutdownMonitorTest
{
@Test
public void testShutdown ()
throws Exception
{
//test port and key assignment
ShutdownMonitor.getInstance().setPort(0);
ShutdownMonitor.getInstance().setExitVm(false);
ShutdownMonitor.getInstance().start();
String key = ShutdownMonitor.getInstance().getKey();
int port = ShutdownMonitor.getInstance().getPort();
//try starting a 2nd time (should be ignored)
ShutdownMonitor.getInstance().start();
stop(port,key,true);
assertTrue(!ShutdownMonitor.getInstance().isAlive());
//should be able to change port and key because it is stopped
ShutdownMonitor.getInstance().setPort(0);
ShutdownMonitor.getInstance().setKey("foo");
ShutdownMonitor.getInstance().start();
key = ShutdownMonitor.getInstance().getKey();
port = ShutdownMonitor.getInstance().getPort();
assertTrue(ShutdownMonitor.getInstance().isAlive());
stop(port,key,true);
assertTrue(!ShutdownMonitor.getInstance().isAlive());
}
public void stop (int port, String key, boolean check)
throws Exception
{
Socket s = null;
try
{
//send stop command
s = new Socket(InetAddress.getByName("127.0.0.1"),port);
OutputStream out = s.getOutputStream();
out.write((key + "\r\nstop\r\n").getBytes());
out.flush();
if (check)
{
//wait a little
Thread.currentThread().sleep(600);
//check for stop confirmation
LineNumberReader lin = new LineNumberReader(new InputStreamReader(s.getInputStream()));
String response;
if ((response = lin.readLine()) != null)
{
assertEquals("Stopped", response);
}
else
throw new IllegalStateException("No stop confirmation");
}
}
finally
{
if (s != null) s.close();
}
}
}

View File

@ -37,6 +37,7 @@ import org.eclipse.jetty.server.handler.HandlerWrapper;
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
import org.eclipse.jetty.toolchain.test.OS;
import org.eclipse.jetty.toolchain.test.annotation.Stress;
import org.eclipse.jetty.toolchain.test.PropertyFlag;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
@ -130,35 +131,37 @@ public class StressTest
}
@Test
@Stress("Much threading")
public void testNonPersistent() throws Throwable
{
// TODO needs to be further investigated
assumeTrue(!OS.IS_OSX);
assumeTrue(!OS.IS_OSX || PropertyFlag.isEnabled("test.stress"));
doThreads(10,10,false);
Thread.sleep(1000);
doThreads(20,20,false);
Thread.sleep(1000);
doThreads(200,10,false);
Thread.sleep(1000);
doThreads(200,200,false);
if (PropertyFlag.isEnabled("test.stress"))
{
doThreads(20,20,false);
Thread.sleep(1000);
doThreads(200,10,false);
Thread.sleep(1000);
doThreads(200,200,false);
}
}
@Test
@Stress("Much threading")
public void testPersistent() throws Throwable
{
// TODO needs to be further investigated
assumeTrue(!OS.IS_OSX);
assumeTrue(!OS.IS_OSX || PropertyFlag.isEnabled("test.stress"));
doThreads(10,10,true);
Thread.sleep(1000);
doThreads(40,40,true);
Thread.sleep(1000);
doThreads(200,10,true);
Thread.sleep(1000);
doThreads(200,200,true);
if (PropertyFlag.isEnabled("test.stress"))
{
doThreads(40,40,true);
Thread.sleep(1000);
doThreads(200,10,true);
Thread.sleep(1000);
doThreads(200,200,true);
}
}
private void doThreads(int threadCount, final int loops, final boolean persistent) throws Throwable

View File

@ -97,7 +97,19 @@ public class FilterHolder extends Holder<Filter>
super.stop();
throw new IllegalStateException(msg);
}
}
/* ------------------------------------------------------------ */
@Override
public void initialize() throws Exception
{
super.initialize();
if (_filter==null)
{
try
@ -123,6 +135,7 @@ public class FilterHolder extends Holder<Filter>
_filter.init(_config);
}
/* ------------------------------------------------------------ */
@Override
public void doStop()

View File

@ -82,6 +82,19 @@ public class Holder<T> extends AbstractLifeCycle implements Dumpable
{
return _extInstance;
}
/* ------------------------------------------------------------ */
/**
* Do any setup necessary after starting
* @throws Exception
*/
public void initialize()
throws Exception
{
if (!isStarted())
throw new IllegalStateException("Not started: "+this);
}
/* ------------------------------------------------------------ */
@SuppressWarnings("unchecked")

View File

@ -741,6 +741,7 @@ public class ServletHandler extends ScopedHandler
try
{
h.start();
h.initialize();
}
catch (Exception e)
{

View File

@ -280,7 +280,7 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
_enabled = enabled;
}
/* ------------------------------------------------------------ */
public void doStart()
throws Exception
@ -319,7 +319,17 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
if (_class!=null && javax.servlet.SingleThreadModel.class.isAssignableFrom(_class))
_servlet = new SingleThreadedWrapper();
}
/* ------------------------------------------------------------ */
@Override
public void initialize ()
throws Exception
{
super.initialize();
if (_extInstance || _initOnStartup)
{
try
@ -335,7 +345,8 @@ public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope
}
}
}
/* ------------------------------------------------------------ */
public void doStop()
throws Exception

View File

@ -98,7 +98,9 @@ public abstract class AbstractDoSFilterTest
public void startFilters() throws Exception
{
_dosFilter.start();
_dosFilter.initialize();
_timeoutFilter.start();
_timeoutFilter.initialize();
}
@After

View File

@ -13,7 +13,7 @@
<name>Jetty :: SPDY :: Parent</name>
<properties>
<npn.version>1.1.2.v20130305</npn.version>
<npn.version>1.1.5.v20130313</npn.version>
<npn.api.version>1.1.0.v20120525</npn.api.version>
</properties>

View File

@ -963,6 +963,7 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
{
FrameBytes frameBytes = null;
ByteBuffer buffer = null;
boolean failFrameBytes = false;
synchronized (queue)
{
if (flushing || queue.isEmpty())
@ -982,11 +983,7 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
{
queue.remove(i);
if (stream != null && stream.isReset() && !(frameBytes instanceof ControlFrameBytes))
{
frameBytes.fail(new StreamException(stream.getId(), StreamStatus.INVALID_STREAM,
"Stream: " + stream + " is reset!"));
return;
}
failFrameBytes = true;
break;
}
@ -1001,10 +998,21 @@ public class StandardSession implements ISession, Parser.Listener, Dumpable
if (buffer == null)
return;
flushing = true;
LOG.debug("Flushing {}, {} frame(s) in queue", frameBytes, queue.size());
if (!failFrameBytes)
{
flushing = true;
LOG.debug("Flushing {}, {} frame(s) in queue", frameBytes, queue.size());
}
}
if (failFrameBytes)
{
frameBytes.fail(new StreamException(frameBytes.getStream().getId(), StreamStatus.INVALID_STREAM,
"Stream: " + frameBytes.getStream() + " is reset!"));
}
else
{
write(buffer, frameBytes);
}
write(buffer, frameBytes);
}
private void append(FrameBytes frameBytes)

View File

@ -96,6 +96,12 @@
<artifactId>jetty-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlets</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.npn</groupId>
<artifactId>npn-api</artifactId>

View File

@ -24,6 +24,18 @@
<Set name="KeyManagerPassword">OBF:1u2u1wml1z7s1z7a1wnl1u2g</Set>
<Set name="TrustStorePath"><Property name="jetty.home" default="." />/etc/keystore</Set>
<Set name="TrustStorePassword">OBF:1vny1zlo1x8e1vnw1vn61x8g1zlu1vn4</Set>
<Set name="EndpointIdentificationAlgorithm"></Set>
<Set name="ExcludeCipherSuites">
<Array type="String">
<Item>SSL_RSA_WITH_DES_CBC_SHA</Item>
<Item>SSL_DHE_RSA_WITH_DES_CBC_SHA</Item>
<Item>SSL_DHE_DSS_WITH_DES_CBC_SHA</Item>
<Item>SSL_RSA_EXPORT_WITH_RC4_40_MD5</Item>
<Item>SSL_RSA_EXPORT_WITH_DES40_CBC_SHA</Item>
<Item>SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA</Item>
<Item>SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA</Item>
</Array>
</Set>
</New>
<!-- =========================================================== -->

View File

@ -37,6 +37,7 @@ import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.HttpTransport;
import org.eclipse.jetty.spdy.StreamException;
import org.eclipse.jetty.spdy.api.ByteBufferDataInfo;
import org.eclipse.jetty.spdy.api.HeadersInfo;
import org.eclipse.jetty.spdy.api.PushInfo;
import org.eclipse.jetty.spdy.api.ReplyInfo;
import org.eclipse.jetty.spdy.api.SPDY;
@ -198,6 +199,8 @@ public class HttpTransportOverSPDY implements HttpTransport
{
if (!stream.isUnidirectional())
stream.reply(replyInfo, new Callback.Adapter());
else
stream.headers(new HeadersInfo(replyInfo.getHeaders(), replyInfo.isClose()), new Callback.Adapter());
Fields responseHeaders = replyInfo.getHeaders();
short version = stream.getSession().getVersion();
@ -230,19 +233,17 @@ public class HttpTransportOverSPDY implements HttpTransport
private Fields createRequestHeaders(Fields.Field scheme, Fields.Field host, Fields.Field uri, String pushResourcePath)
{
final Fields requestHeaders = new Fields();
final Fields newRequestHeaders = new Fields(requestHeaders, false);
short version = stream.getSession().getVersion();
requestHeaders.put(HTTPSPDYHeader.METHOD.name(version), "GET");
requestHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
requestHeaders.put(scheme);
requestHeaders.put(host);
requestHeaders.put(HTTPSPDYHeader.URI.name(version), pushResourcePath);
newRequestHeaders.put(HTTPSPDYHeader.METHOD.name(version), "GET");
newRequestHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
newRequestHeaders.put(scheme);
newRequestHeaders.put(host);
newRequestHeaders.put(HTTPSPDYHeader.URI.name(version), pushResourcePath);
String referrer = scheme.value() + "://" + host.value() + uri.value();
requestHeaders.put("referer", referrer);
// Remember support for gzip encoding
requestHeaders.put(requestHeaders.get("accept-encoding"));
requestHeaders.put("x-spdy-push", "true");
return requestHeaders;
newRequestHeaders.put("referer", referrer);
newRequestHeaders.put("x-spdy-push", "true");
return newRequestHeaders;
}
private Fields createPushHeaders(Fields.Field scheme, Fields.Field host, String pushResourcePath)
@ -257,8 +258,6 @@ public class HttpTransportOverSPDY implements HttpTransport
pushHeaders.put(scheme);
pushHeaders.put(host);
}
pushHeaders.put(HTTPSPDYHeader.STATUS.name(version), "200");
pushHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");
return pushHeaders;
}

View File

@ -32,7 +32,9 @@ import org.eclipse.jetty.server.ConnectionFactory;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.servlets.gzip.GzipHandler;
import org.eclipse.jetty.spdy.api.DataInfo;
import org.eclipse.jetty.spdy.api.HeadersInfo;
import org.eclipse.jetty.spdy.api.PushInfo;
import org.eclipse.jetty.spdy.api.ReplyInfo;
import org.eclipse.jetty.spdy.api.RstInfo;
@ -155,7 +157,8 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
private InetSocketAddress createServer() throws Exception
{
return startHTTPServer(version, new AbstractHandler()
GzipHandler gzipHandler = new GzipHandler();
gzipHandler.setHandler(new AbstractHandler()
{
@Override
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
@ -171,6 +174,7 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
baseRequest.setHandled(true);
}
});
return startHTTPServer(version, gzipHandler);
}
private Session sendMainRequestAndCSSRequest() throws Exception
@ -240,6 +244,7 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
final CountDownLatch mainStreamLatch = new CountDownLatch(2);
final CountDownLatch pushDataLatch = new CountDownLatch(1);
final CountDownLatch pushSynHeadersValid = new CountDownLatch(1);
final CountDownLatch pushResponseHeaders = new CountDownLatch(1);
Session session2 = startClient(version, serverAddress, null);
session2.syn(new SynInfo(mainRequestHeaders, true), new StreamFrameListener.Adapter()
{
@ -257,10 +262,19 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
is(true));
return new StreamFrameListener.Adapter()
{
@Override
public void onHeaders(Stream stream, HeadersInfo headersInfo)
{
Fields headers = headersInfo.getHeaders();
if (validateHeader(headers, HTTPSPDYHeader.STATUS.name(version), "200 OK")
&& validateHeader(headers, HTTPSPDYHeader.VERSION.name(version),
"HTTP/1.1") && validateHeader(headers, "content-encoding", "gzip"))
pushResponseHeaders.countDown();
}
@Override
public void onData(Stream stream, DataInfo dataInfo)
{
dataInfo.consume(dataInfo.length());
if (dataInfo.isClose())
pushDataLatch.countDown();
@ -797,9 +811,7 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
private void validateHeaders(Fields headers, CountDownLatch pushSynHeadersValid)
{
if (validateHeader(headers, HTTPSPDYHeader.STATUS.name(version), "200")
&& validateHeader(headers, HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1")
&& validateUriHeader(headers))
if (validateUriHeader(headers))
pushSynHeadersValid.countDown();
}
@ -808,7 +820,7 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
Fields.Field header = headers.get(name);
if (header != null && expectedValue.equals(header.value()))
return true;
System.out.println(name + " not valid! " + headers);
System.out.println(name + " not valid! Expected: " + expectedValue + " headers received:" + headers);
return false;
}
@ -842,6 +854,7 @@ public class ReferrerPushStrategyTest extends AbstractHTTPSPDYTest
Fields requestHeaders = new Fields();
requestHeaders.put("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:16.0) " +
"Gecko/20100101 Firefox/16.0");
requestHeaders.put("accept-encoding", "gzip");
requestHeaders.put(HTTPSPDYHeader.METHOD.name(version), "GET");
requestHeaders.put(HTTPSPDYHeader.URI.name(version), resource);
requestHeaders.put(HTTPSPDYHeader.VERSION.name(version), "HTTP/1.1");

View File

@ -62,6 +62,9 @@ import org.junit.runner.Description;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
@RunWith(value = Parameterized.class)
public class ProxySPDYToSPDYTest
{
@ -186,6 +189,40 @@ public class ProxySPDYToSPDYTest
client.goAway(new GoAwayInfo(5, TimeUnit.SECONDS));
}
@Test
public void testSYNThenRSTFromUpstreamServer() throws Exception
{
final String header = "foo";
InetSocketAddress proxyAddress = startProxy(startServer(new ServerSessionFrameListener.Adapter()
{
@Override
public StreamFrameListener onSyn(Stream stream, SynInfo synInfo)
{
Fields requestHeaders = synInfo.getHeaders();
Assert.assertNotNull(requestHeaders.get("via"));
Assert.assertNotNull(requestHeaders.get(header));
stream.getSession().rst(new RstInfo(stream.getId(), StreamStatus.REFUSED_STREAM), new Callback.Adapter());
return null;
}
}));
proxyConnector.addConnectionFactory(proxyConnector.getConnectionFactory("spdy/" + version));
final CountDownLatch resetLatch = new CountDownLatch(1);
Session client = factory.newSPDYClient(version).connect(proxyAddress, new SessionFrameListener.Adapter()
{
@Override
public void onRst(Session session, RstInfo rstInfo)
{
resetLatch.countDown();
}
}).get(5, TimeUnit.SECONDS);
Fields headers = SPDYTestUtils.createHeaders("localhost", proxyAddress.getPort(), version, "GET", "/");
headers.put(header, "bar");
client.syn(new SynInfo(headers, true), new StreamFrameListener.Adapter());
assertThat("reset is received by client", resetLatch.await(5, TimeUnit.SECONDS), is(true));
}
@Test
public void testSYNThenREPLYAndDATA() throws Exception

View File

@ -53,12 +53,12 @@ public class BlockingArrayQueue<E> extends AbstractList<E> implements BlockingQu
* by 15 slots to avoid false sharing with the array length
* (stored before the first element of the array itself).
*/
private static final int HEAD_OFFSET = 15;
private static final int HEAD_OFFSET = MemoryUtils.getIntegersPerCacheLine() - 1;
/**
* The tail offset in the {@link #_indexes} array, displaced
* by 16 slots from the head to avoid false sharing with it.
*/
private static final int TAIL_OFFSET = 31;
private static final int TAIL_OFFSET = HEAD_OFFSET + MemoryUtils.getIntegersPerCacheLine();
/**
* Default initial capacity, 128.
*/

View File

@ -0,0 +1,418 @@
//
// ========================================================================
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util;
import java.util.Collection;
import java.util.Objects;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLongArray;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Common functionality for a blocking version of {@link ConcurrentArrayQueue}.
*
* @see Unbounded
* @see Bounded
* @param <E>
*/
public abstract class ConcurrentArrayBlockingQueue<E> extends ConcurrentArrayQueue<E> implements BlockingQueue<E>
{
private final Lock _lock = new ReentrantLock();
private final Condition _consumer = _lock.newCondition();
public ConcurrentArrayBlockingQueue(int blockSize)
{
super(blockSize);
}
@Override
public E poll()
{
E result = super.poll();
if (result != null && decrementAndGetSize() > 0)
signalConsumer();
return result;
}
@Override
public boolean remove(Object o)
{
boolean result = super.remove(o);
if (result && decrementAndGetSize() > 0)
signalConsumer();
return result;
}
protected abstract int decrementAndGetSize();
protected void signalConsumer()
{
final Lock lock = _lock;
lock.lock();
try
{
_consumer.signal();
}
finally
{
lock.unlock();
}
}
@Override
public E take() throws InterruptedException
{
while (true)
{
E result = poll();
if (result != null)
return result;
final Lock lock = _lock;
lock.lockInterruptibly();
try
{
if (size() == 0)
{
_consumer.await();
}
}
finally
{
lock.unlock();
}
}
}
@Override
public E poll(long timeout, TimeUnit unit) throws InterruptedException
{
long nanos = unit.toNanos(timeout);
while (true)
{
// TODO should reduce nanos if we spin here
E result = poll();
if (result != null)
return result;
final Lock lock = _lock;
lock.lockInterruptibly();
try
{
if (size() == 0)
{
if (nanos <= 0)
return null;
nanos = _consumer.awaitNanos(nanos);
}
}
finally
{
lock.unlock();
}
}
}
@Override
public int drainTo(Collection<? super E> c)
{
return drainTo(c, Integer.MAX_VALUE);
}
@Override
public int drainTo(Collection<? super E> c, int maxElements)
{
if (c == this)
throw new IllegalArgumentException();
int added = 0;
while (added < maxElements)
{
E element = poll();
if (element == null)
break;
c.add(element);
++added;
}
return added;
}
/**
* An unbounded, blocking version of {@link ConcurrentArrayQueue}.
*
* @param <E>
*/
public static class Unbounded<E> extends ConcurrentArrayBlockingQueue<E>
{
private static final int SIZE_LEFT_OFFSET = MemoryUtils.getLongsPerCacheLine() - 1;
private static final int SIZE_RIGHT_OFFSET = SIZE_LEFT_OFFSET + MemoryUtils.getLongsPerCacheLine();
private final AtomicLongArray _sizes = new AtomicLongArray(SIZE_RIGHT_OFFSET+1);
public Unbounded()
{
this(DEFAULT_BLOCK_SIZE);
}
public Unbounded(int blockSize)
{
super(blockSize);
}
@Override
public boolean offer(E item)
{
boolean result = super.offer(item);
if (result && getAndIncrementSize() == 0)
signalConsumer();
return result;
}
private int getAndIncrementSize()
{
long sizeRight = _sizes.getAndIncrement(SIZE_RIGHT_OFFSET);
long sizeLeft = _sizes.get(SIZE_LEFT_OFFSET);
return (int)(sizeRight - sizeLeft);
}
@Override
protected int decrementAndGetSize()
{
long sizeLeft = _sizes.incrementAndGet(SIZE_LEFT_OFFSET);
long sizeRight = _sizes.get(SIZE_RIGHT_OFFSET);
return (int)(sizeRight - sizeLeft);
}
@Override
public int size()
{
long sizeLeft = _sizes.get(SIZE_LEFT_OFFSET);
long sizeRight = _sizes.get(SIZE_RIGHT_OFFSET);
return (int)(sizeRight - sizeLeft);
}
@Override
public int remainingCapacity()
{
return Integer.MAX_VALUE;
}
@Override
public void put(E element) throws InterruptedException
{
offer(element);
}
@Override
public boolean offer(E element, long timeout, TimeUnit unit) throws InterruptedException
{
return offer(element);
}
}
/**
* A bounded, blocking version of {@link ConcurrentArrayQueue}.
*
* @param <E>
*/
public static class Bounded<E> extends ConcurrentArrayBlockingQueue<E>
{
private final AtomicInteger _size = new AtomicInteger();
private final Lock _lock = new ReentrantLock();
private final Condition _producer = _lock.newCondition();
private final int _capacity;
public Bounded(int capacity)
{
this(DEFAULT_BLOCK_SIZE, capacity);
}
public Bounded(int blockSize, int capacity)
{
super(blockSize);
this._capacity = capacity;
}
@Override
public boolean offer(E item)
{
while (true)
{
int size = size();
int nextSize = size + 1;
if (nextSize > _capacity)
return false;
if (_size.compareAndSet(size, nextSize))
{
if (super.offer(item))
{
if (size == 0)
signalConsumer();
return true;
}
else
{
decrementAndGetSize();
}
}
}
}
@Override
public E poll()
{
E result = super.poll();
if (result != null)
signalProducer();
return result;
}
@Override
public boolean remove(Object o)
{
boolean result = super.remove(o);
if (result)
signalProducer();
return result;
}
@Override
protected int decrementAndGetSize()
{
return _size.decrementAndGet();
}
@Override
public int size()
{
return _size.get();
}
@Override
public int remainingCapacity()
{
return _capacity - size();
}
@Override
public void put(E item) throws InterruptedException
{
item = Objects.requireNonNull(item);
while (true)
{
final Lock lock = _lock;
lock.lockInterruptibly();
try
{
if (size() == _capacity)
_producer.await();
}
finally
{
lock.unlock();
}
if (offer(item))
break;
}
}
@Override
public boolean offer(E item, long timeout, TimeUnit unit) throws InterruptedException
{
item = Objects.requireNonNull(item);
long nanos = unit.toNanos(timeout);
while (true)
{
final Lock lock = _lock;
lock.lockInterruptibly();
try
{
if (size() == _capacity)
{
if (nanos <= 0)
return false;
nanos = _producer.awaitNanos(nanos);
}
}
finally
{
lock.unlock();
}
if (offer(item))
break;
}
return true;
}
@Override
public int drainTo(Collection<? super E> c, int maxElements)
{
int result = super.drainTo(c, maxElements);
if (result > 0)
signalProducers();
return result;
}
@Override
public void clear()
{
super.clear();
signalProducers();
}
private void signalProducer()
{
final Lock lock = _lock;
lock.lock();
try
{
_producer.signal();
}
finally
{
lock.unlock();
}
}
private void signalProducers()
{
final Lock lock = _lock;
lock.lock();
try
{
_producer.signalAll();
}
finally
{
lock.unlock();
}
}
}
}

View File

@ -0,0 +1,570 @@
//
// ========================================================================
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util;
import java.util.AbstractQueue;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicIntegerArray;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicReferenceArray;
/**
* A concurrent, unbounded implementation of {@link Queue} that uses singly-linked array blocks
* to store elements.
* <p/>
* This class is a drop-in replacement for {@link ConcurrentLinkedQueue}, with similar performance
* but producing less garbage because arrays are used to store elements rather than nodes.
* <p/>
* The algorithm used is a variation of the algorithm from Gidenstam, Sundell and Tsigas
* (http://www.adm.hb.se/~AGD/Presentations/CacheAwareQueue_OPODIS.pdf).
*
* @param <T>
*/
public class ConcurrentArrayQueue<T> extends AbstractQueue<T>
{
public static final int DEFAULT_BLOCK_SIZE = 512;
public static final Object REMOVED_ELEMENT = new Object()
{
@Override
public String toString()
{
return "X";
}
};
private static final int HEAD_OFFSET = MemoryUtils.getIntegersPerCacheLine() - 1;
private static final int TAIL_OFFSET = MemoryUtils.getIntegersPerCacheLine()*2 -1;
private final AtomicReferenceArray<Block<T>> _blocks = new AtomicReferenceArray<>(TAIL_OFFSET + 1);
private final int _blockSize;
public ConcurrentArrayQueue()
{
this(DEFAULT_BLOCK_SIZE);
}
public ConcurrentArrayQueue(int blockSize)
{
_blockSize = blockSize;
Block<T> block = newBlock();
_blocks.set(HEAD_OFFSET,block);
_blocks.set(TAIL_OFFSET,block);
}
public int getBlockSize()
{
return _blockSize;
}
protected Block<T> getHeadBlock()
{
return _blocks.get(HEAD_OFFSET);
}
protected Block<T> getTailBlock()
{
return _blocks.get(TAIL_OFFSET);
}
@Override
public boolean offer(T item)
{
item = Objects.requireNonNull(item);
final Block<T> initialTailBlock = getTailBlock();
Block<T> currentTailBlock = initialTailBlock;
int tail = currentTailBlock.tail();
while (true)
{
if (tail == getBlockSize())
{
Block<T> nextTailBlock = currentTailBlock.next();
if (nextTailBlock == null)
{
nextTailBlock = newBlock();
if (currentTailBlock.link(nextTailBlock))
{
// Linking succeeded, loop
currentTailBlock = nextTailBlock;
}
else
{
// Concurrent linking, use other block and loop
currentTailBlock = currentTailBlock.next();
}
}
else
{
// Not at last block, loop
currentTailBlock = nextTailBlock;
}
tail = currentTailBlock.tail();
}
else
{
if (currentTailBlock.peek(tail) == null)
{
if (currentTailBlock.store(tail, item))
{
// Item stored
break;
}
else
{
// Concurrent store, try next index
++tail;
}
}
else
{
// Not free, try next index
++tail;
}
}
}
updateTailBlock(initialTailBlock, currentTailBlock);
return true;
}
private void updateTailBlock(Block<T> oldTailBlock, Block<T> newTailBlock)
{
// Update the tail block pointer if needs to
if (oldTailBlock != newTailBlock)
{
// The tail block pointer is allowed to lag behind.
// If this update fails, it means that other threads
// have filled this block and installed a new one.
casTailBlock(oldTailBlock, newTailBlock);
}
}
protected boolean casTailBlock(Block<T> current, Block<T> update)
{
return _blocks.compareAndSet(TAIL_OFFSET,current,update);
}
@Override
public T poll()
{
final Block<T> initialHeadBlock = getHeadBlock();
Block<T> currentHeadBlock = initialHeadBlock;
int head = currentHeadBlock.head();
T result = null;
while (true)
{
if (head == getBlockSize())
{
Block<T> nextHeadBlock = currentHeadBlock.next();
if (nextHeadBlock == null)
{
// We could have read that the next head block was null
// but another thread allocated a new block and stored a
// new item. This thread could not detect this, but that
// is ok, otherwise we would not be able to exit this loop.
// Queue is empty
break;
}
else
{
// Use next block and loop
currentHeadBlock = nextHeadBlock;
head = currentHeadBlock.head();
}
}
else
{
Object element = currentHeadBlock.peek(head);
if (element == REMOVED_ELEMENT)
{
// Already removed, try next index
++head;
}
else
{
result = (T)element;
if (result != null)
{
if (currentHeadBlock.remove(head, result, true))
{
// Item removed
break;
}
else
{
// Concurrent remove, try next index
++head;
}
}
else
{
// Queue is empty
break;
}
}
}
}
updateHeadBlock(initialHeadBlock, currentHeadBlock);
return result;
}
private void updateHeadBlock(Block<T> oldHeadBlock, Block<T> newHeadBlock)
{
// Update the head block pointer if needs to
if (oldHeadBlock != newHeadBlock)
{
// The head block pointer lagged behind.
// If this update fails, it means that other threads
// have emptied this block and pointed to a new one.
casHeadBlock(oldHeadBlock, newHeadBlock);
}
}
protected boolean casHeadBlock(Block<T> current, Block<T> update)
{
return _blocks.compareAndSet(HEAD_OFFSET,current,update);
}
@Override
public T peek()
{
Block<T> currentHeadBlock = getHeadBlock();
int head = currentHeadBlock.head();
while (true)
{
if (head == getBlockSize())
{
Block<T> nextHeadBlock = currentHeadBlock.next();
if (nextHeadBlock == null)
{
// Queue is empty
return null;
}
else
{
// Use next block and loop
currentHeadBlock = nextHeadBlock;
head = currentHeadBlock.head();
}
}
else
{
Object element = currentHeadBlock.peek(head);
if (element == REMOVED_ELEMENT)
{
// Already removed, try next index
++head;
}
else
{
return (T)element;
}
}
}
}
@Override
public boolean remove(Object o)
{
Block<T> currentHeadBlock = getHeadBlock();
int head = currentHeadBlock.head();
boolean result = false;
while (true)
{
if (head == getBlockSize())
{
Block<T> nextHeadBlock = currentHeadBlock.next();
if (nextHeadBlock == null)
{
// Not found
break;
}
else
{
// Use next block and loop
currentHeadBlock = nextHeadBlock;
head = currentHeadBlock.head();
}
}
else
{
Object element = currentHeadBlock.peek(head);
if (element == REMOVED_ELEMENT)
{
// Removed, try next index
++head;
}
else
{
if (element == null)
{
// Not found
break;
}
else
{
if (element.equals(o))
{
// Found
if (currentHeadBlock.remove(head, o, false))
{
result = true;
break;
}
else
{
++head;
}
}
else
{
// Not the one we're looking for
++head;
}
}
}
}
}
return result;
}
@Override
public boolean removeAll(Collection<?> c)
{
// TODO: super invocations are based on iterator.remove(), which throws
return super.removeAll(c);
}
@Override
public boolean retainAll(Collection<?> c)
{
// TODO: super invocations are based on iterator.remove(), which throws
return super.retainAll(c);
}
@Override
public Iterator<T> iterator()
{
final List<Object[]> blocks = new ArrayList<>();
Block<T> currentHeadBlock = getHeadBlock();
while (currentHeadBlock != null)
{
Object[] elements = currentHeadBlock.arrayCopy();
blocks.add(elements);
currentHeadBlock = currentHeadBlock.next();
}
return new Iterator<T>()
{
private int blockIndex;
private int index;
@Override
public boolean hasNext()
{
while (true)
{
if (blockIndex == blocks.size())
return false;
Object element = blocks.get(blockIndex)[index];
if (element == null)
return false;
if (element != REMOVED_ELEMENT)
return true;
advance();
}
}
@Override
public T next()
{
while (true)
{
if (blockIndex == blocks.size())
throw new NoSuchElementException();
Object element = blocks.get(blockIndex)[index];
if (element == null)
throw new NoSuchElementException();
advance();
if (element != REMOVED_ELEMENT)
return (T)element;
}
}
private void advance()
{
if (++index == getBlockSize())
{
index = 0;
++blockIndex;
}
}
@Override
public void remove()
{
throw new UnsupportedOperationException();
}
};
}
@Override
public int size()
{
Block<T> currentHeadBlock = getHeadBlock();
int head = currentHeadBlock.head();
int size = 0;
while (true)
{
if (head == getBlockSize())
{
Block<T> nextHeadBlock = currentHeadBlock.next();
if (nextHeadBlock == null)
{
break;
}
else
{
// Use next block and loop
currentHeadBlock = nextHeadBlock;
head = currentHeadBlock.head();
}
}
else
{
Object element = currentHeadBlock.peek(head);
if (element == REMOVED_ELEMENT)
{
// Already removed, try next index
++head;
}
else if (element != null)
{
++size;
++head;
}
else
{
break;
}
}
}
return size;
}
protected Block<T> newBlock()
{
return new Block<>(getBlockSize());
}
protected int getBlockCount()
{
int result = 0;
Block<T> headBlock = getHeadBlock();
while (headBlock != null)
{
++result;
headBlock = headBlock.next();
}
return result;
}
protected static final class Block<E>
{
private static final int headOffset = MemoryUtils.getIntegersPerCacheLine()-1;
private static final int tailOffset = MemoryUtils.getIntegersPerCacheLine()*2-1;
private final AtomicReferenceArray<Object> elements;
private final AtomicReference<Block<E>> next = new AtomicReference<>();
private final AtomicIntegerArray indexes = new AtomicIntegerArray(TAIL_OFFSET+1);
protected Block(int blockSize)
{
elements = new AtomicReferenceArray<>(blockSize);
}
public Object peek(int index)
{
return elements.get(index);
}
public boolean store(int index, E item)
{
boolean result = elements.compareAndSet(index, null, item);
if (result)
indexes.incrementAndGet(tailOffset);
return result;
}
public boolean remove(int index, Object item, boolean updateHead)
{
boolean result = elements.compareAndSet(index, item, REMOVED_ELEMENT);
if (result && updateHead)
indexes.incrementAndGet(headOffset);
return result;
}
public Block<E> next()
{
return next.get();
}
public boolean link(Block<E> nextBlock)
{
return next.compareAndSet(null, nextBlock);
}
public int head()
{
return indexes.get(headOffset);
}
public int tail()
{
return indexes.get(tailOffset);
}
public Object[] arrayCopy()
{
Object[] result = new Object[elements.length()];
for (int i = 0; i < result.length; ++i)
result[i] = elements.get(i);
return result;
}
}
}

View File

@ -0,0 +1,71 @@
//
// ========================================================================
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util;
import java.security.AccessController;
import java.security.PrivilegedAction;
/**
* {@link MemoryUtils} provides an abstraction over memory properties and operations.
* <p />
*/
public class MemoryUtils
{
private static final int cacheLineBytes;
static
{
final int defaultValue = 64;
int value = defaultValue;
try
{
value = Integer.parseInt(AccessController.doPrivileged(new PrivilegedAction<String>()
{
@Override
public String run()
{
return System.getProperty("org.eclipse.jetty.util.cacheLineBytes", String.valueOf(defaultValue));
}
}));
}
catch (Exception ignored)
{
}
cacheLineBytes = value;
}
private MemoryUtils()
{
}
public static int getCacheLineBytes()
{
return cacheLineBytes;
}
public static int getIntegersPerCacheLine()
{
return getCacheLineBytes() >> 2;
}
public static int getLongsPerCacheLine()
{
return getCacheLineBytes() >> 3;
}
}

View File

@ -0,0 +1,80 @@
//
// ========================================================================
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util.component;
import java.io.FileWriter;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/* ------------------------------------------------------------ */
/** A LifeCycle Listener that writes state changes to a file.
* <p>This can be used with the jetty.sh script to wait for successful startup.
*/
public class FileNoticeLifeCycleListener implements LifeCycle.Listener
{
Logger LOG = Log.getLogger(FileNoticeLifeCycleListener.class);
private final String _filename;
public FileNoticeLifeCycleListener(String filename)
{
_filename=filename;
}
private void writeState(String action, LifeCycle lifecycle)
{
try
{
FileWriter out = new FileWriter(_filename,true);
out.append(action).append(" ").append(lifecycle.toString()).append("\n");
out.close();
}
catch(Exception e)
{
LOG.warn(e);
}
}
public void lifeCycleStarting(LifeCycle event)
{
writeState("STARTING",event);
}
public void lifeCycleStarted(LifeCycle event)
{
writeState("STARTED",event);
}
public void lifeCycleFailure(LifeCycle event, Throwable cause)
{
writeState("FAILED",event);
}
public void lifeCycleStopping(LifeCycle event)
{
writeState("STOPPING",event);
}
public void lifeCycleStopped(LifeCycle event)
{
writeState("STOPPED",event);
}
}

View File

@ -32,6 +32,9 @@ import java.util.List;
import java.util.StringTokenizer;
import org.eclipse.jetty.util.URIUtil;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
/**
* A collection of resources (dirs).
@ -45,6 +48,7 @@ import org.eclipse.jetty.util.URIUtil;
*/
public class ResourceCollection extends Resource
{
private static final Logger LOG = Log.getLogger(ResourceCollection.class);
private Resource[] _resources;
/* ------------------------------------------------------------ */
@ -167,20 +171,25 @@ public class ResourceCollection extends Resource
" argument must be a string containing one or more comma-separated resource strings.");
}
_resources = new Resource[len];
List<Resource> resources = new ArrayList<>();
try
{
for(int i=0; tokenizer.hasMoreTokens(); i++)
while(tokenizer.hasMoreTokens())
{
_resources[i] = Resource.newResource(tokenizer.nextToken().trim());
if(!_resources[i].exists() || !_resources[i].isDirectory())
throw new IllegalArgumentException(_resources[i] + " is not an existing directory.");
Resource resource = Resource.newResource(tokenizer.nextToken().trim());
if(!resource.exists() || !resource.isDirectory())
LOG.warn(" !exist "+resource);
else
resources.add(resource);
}
}
catch(Exception e)
{
throw new RuntimeException(e);
}
_resources = resources.toArray(new Resource[resources.size()]);
}
/* ------------------------------------------------------------ */

View File

@ -194,7 +194,7 @@ public class SslContextFactory extends AbstractLifeCycle
private SSLContext _context;
/** EndpointIdentificationAlgorithm - when set to "HTTPS" hostname verification will be enabled */
private String _endpointIdentificationAlgorithm = "HTTPS";
private String _endpointIdentificationAlgorithm = null;
private boolean _trustAll;

View File

@ -54,7 +54,7 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
private final AtomicLong _lastShrink = new AtomicLong();
private final ConcurrentLinkedQueue<Thread> _threads = new ConcurrentLinkedQueue<>();
private final Object _joinLock = new Object();
private BlockingQueue<Runnable> _jobs;
private final BlockingQueue<Runnable> _jobs;
private String _name = "qtp" + hashCode();
private int _idleTimeout;
private int _maxThreads;
@ -79,11 +79,21 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
}
public QueuedThreadPool(int maxThreads, int minThreads, int idleTimeout)
{
this(maxThreads, minThreads, 60000,null);
}
public QueuedThreadPool(@Name("maxThreads") int maxThreads, @Name("minThreads") int minThreads, @Name("idleTimeout") int idleTimeout, @Name("queue") BlockingQueue<Runnable> queue)
{
setMinThreads(minThreads);
setMaxThreads(maxThreads);
setIdleTimeout(idleTimeout);
setStopTimeout(5000);
if (queue==null)
queue=new BlockingArrayQueue<Runnable>(_minThreads, _minThreads);// TODO ConcurrentArrayBlockingQueue.Unbounded<Runnable>();
_jobs=queue;
}
@Override
@ -92,9 +102,6 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
super.doStart();
_threadsStarted.set(0);
if (_jobs == null)
setQueue(new BlockingArrayQueue<Runnable>(_minThreads, _minThreads));
startThreads(_minThreads);
}
@ -602,7 +609,7 @@ public class QueuedThreadPool extends AbstractLifeCycle implements SizedThreadPo
*/
public void setQueue(BlockingQueue<Runnable> queue)
{
_jobs = queue;
throw new UnsupportedOperationException("Use constructor injection");
}
/**

View File

@ -0,0 +1,166 @@
//
// ========================================================================
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.toolchain.test.TestTracker;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
public class ConcurrentArrayBlockingQueueUnboundedTest extends ConcurrentArrayQueueTest
{
@Rule
public final TestTracker tracker = new TestTracker();
@Override
protected ConcurrentArrayBlockingQueue<Integer> newConcurrentArrayQueue(int blockSize)
{
return new ConcurrentArrayBlockingQueue.Unbounded<>(blockSize);
}
@Test
public void testOfferTake() throws Exception
{
ConcurrentArrayBlockingQueue<Integer> queue = newConcurrentArrayQueue(32);
Integer item = 1;
Assert.assertTrue(queue.offer(item));
Integer result = queue.take();
Assert.assertSame(item, result);
}
@Test
public void testTimedPollOffer() throws Exception
{
final ConcurrentArrayBlockingQueue<Integer> queue = newConcurrentArrayQueue(32);
final long timeout = 1000;
final Integer item = 1;
new Thread()
{
@Override
public void run()
{
try
{
TimeUnit.MILLISECONDS.sleep(timeout);
queue.offer(item);
}
catch (InterruptedException x)
{
x.printStackTrace();
}
}
}.start();
Integer result = queue.poll(2 * timeout, TimeUnit.MILLISECONDS);
Assert.assertNotNull(result);
}
@Test
public void testConcurrentOfferTake() throws Exception
{
final ConcurrentArrayBlockingQueue<Integer> queue = newConcurrentArrayQueue(512);
int readerCount = 16;
final int factor = 2;
int writerCount = readerCount * factor;
final int iterations = 4096;
for (int runs = 0; runs < 16; ++runs)
{
ExecutorService executor = Executors.newFixedThreadPool(readerCount + writerCount);
List<Future<Integer>> readers = new ArrayList<>();
for (int i = 0; i < readerCount / 2; ++i)
{
final int reader = i;
readers.add(executor.submit(new Callable<Integer>()
{
@Override
public Integer call() throws Exception
{
int sum = 0;
for (int j = 0; j < iterations * factor; ++j)
sum += queue.take();
//System.err.println("Taking reader " + reader + " completed: " + sum);
return sum;
}
}));
readers.add(executor.submit(new Callable<Integer>()
{
@Override
public Integer call() throws Exception
{
int sum = 0;
for (int j = 0; j < iterations * factor; ++j)
sum += queue.poll(5, TimeUnit.SECONDS);
//System.err.println("Polling Reader " + reader + " completed: " + sum);
return sum;
}
}));
}
for (int i = 0; i < writerCount; ++i)
{
final int writer = i;
executor.submit(new Callable<Object>()
{
@Override
public Object call() throws Exception
{
for (int j = 0; j < iterations; ++j)
queue.offer(1);
//System.err.println("Writer " + writer + " completed");
return null;
}
});
}
int sum = 0;
for (Future<Integer> result : readers)
sum += result.get();
Assert.assertEquals(writerCount * iterations, sum);
Assert.assertTrue(queue.isEmpty());
}
}
@Test
public void testDrain() throws Exception
{
final ConcurrentArrayBlockingQueue<Integer> queue = newConcurrentArrayQueue(512);
List<Integer> chunk1 = Arrays.asList(1, 2);
List<Integer> chunk2 = Arrays.asList(3, 4, 5);
queue.addAll(chunk1);
queue.addAll(chunk2);
List<Integer> drainer1 = new ArrayList<>();
queue.drainTo(drainer1, chunk1.size());
List<Integer> drainer2 = new ArrayList<>();
queue.drainTo(drainer2, chunk2.size());
Assert.assertEquals(chunk1, drainer1);
Assert.assertEquals(chunk2, drainer2);
}
}

View File

@ -0,0 +1,172 @@
//
// ========================================================================
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.util;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.junit.Assert;
import org.junit.Test;
public class ConcurrentArrayQueueTest
{
protected ConcurrentArrayQueue<Integer> newConcurrentArrayQueue(int blockSize)
{
return new ConcurrentArrayQueue<>(blockSize);
}
@Test
public void testOfferCreatesBlock()
{
int blockSize = 2;
ConcurrentArrayQueue<Integer> queue = newConcurrentArrayQueue(blockSize);
int blocks = 3;
for (int i = 0; i < blocks * blockSize + 1; ++i)
queue.offer(i);
Assert.assertEquals(blocks + 1, queue.getBlockCount());
}
@Test
public void testPeekRemove() throws Exception
{
int blockSize = 2;
ConcurrentArrayQueue<Integer> queue = newConcurrentArrayQueue(blockSize);
Assert.assertNull(queue.peek());
queue.offer(1);
queue.remove(1);
Assert.assertNull(queue.peek());
int blocks = 3;
int size = blocks * blockSize + 1;
for (int i = 0; i < size; ++i)
queue.offer(i);
for (int i = 0; i < size; ++i)
{
Assert.assertEquals(i, (int)queue.peek());
Assert.assertEquals(i, (int)queue.remove());
}
}
@Test
public void testRemoveObject() throws Exception
{
int blockSize = 2;
ConcurrentArrayQueue<Integer> queue = newConcurrentArrayQueue(blockSize);
queue.add(1);
queue.add(2);
queue.add(3);
Assert.assertFalse(queue.remove(4));
int size = queue.size();
Assert.assertTrue(queue.remove(2));
--size;
Assert.assertEquals(size, queue.size());
Iterator<Integer> iterator = queue.iterator();
Assert.assertTrue(iterator.hasNext());
Assert.assertEquals(1, (int)iterator.next());
Assert.assertTrue(iterator.hasNext());
Assert.assertEquals(3, (int)iterator.next());
queue.offer(4);
++size;
Assert.assertTrue(queue.remove(3));
--size;
Assert.assertEquals(size, queue.size());
iterator = queue.iterator();
Assert.assertTrue(iterator.hasNext());
Assert.assertEquals(1, (int)iterator.next());
Assert.assertTrue(iterator.hasNext());
Assert.assertEquals(4, (int)iterator.next());
Assert.assertTrue(queue.remove(1));
--size;
Assert.assertTrue(queue.remove(4));
--size;
iterator = queue.iterator();
Assert.assertFalse(iterator.hasNext());
}
@Test
public void testSize() throws Exception
{
int blockSize = 2;
ConcurrentArrayQueue<Integer> queue = newConcurrentArrayQueue(blockSize);
queue.offer(1);
Assert.assertEquals(1, queue.size());
queue = newConcurrentArrayQueue(blockSize);
for (int i = 0; i < 2 * blockSize; ++i)
queue.offer(i);
for (int i = 0; i < blockSize; ++i)
queue.poll();
Assert.assertEquals(blockSize, queue.size());
}
@Test
public void testIterator() throws Exception
{
int blockSize = 2;
ConcurrentArrayQueue<Integer> queue = newConcurrentArrayQueue(blockSize);
queue.offer(1);
Iterator<Integer> iterator = queue.iterator();
Assert.assertTrue(iterator.hasNext());
Assert.assertEquals(1, (int)iterator.next());
Assert.assertFalse(iterator.hasNext());
try
{
iterator.next();
Assert.fail();
}
catch (NoSuchElementException ignored)
{
}
// Test block edge
queue = newConcurrentArrayQueue(blockSize);
for (int i = 0; i < blockSize * 2; ++i)
queue.offer(i);
queue.poll();
iterator = queue.iterator();
Assert.assertTrue(iterator.hasNext());
Assert.assertEquals(1, (int)iterator.next());
Assert.assertTrue(iterator.hasNext());
Assert.assertEquals(2, (int)iterator.next());
Assert.assertTrue(iterator.hasNext());
Assert.assertEquals(3, (int)iterator.next());
Assert.assertFalse(iterator.hasNext());
try
{
iterator.next();
Assert.fail();
}
catch (NoSuchElementException ignored)
{
}
}
}

View File

@ -656,6 +656,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
/* ------------------------------------------------------------ */
/** Add to the list of Server classes.
* @see #setServerClasses(String[])
* @see http://www.eclipse.org/jetty/documentation/current/jetty-classloading.html
* @param classOrPackage A fully qualified class name (eg com.foo.MyClass)
* or a qualified package name ending with '.' (eg com.foo.). If the class
* or package has '-' it is excluded from the server classes and order is thus
@ -673,6 +674,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
/* ------------------------------------------------------------ */
/** Prepend to the list of Server classes.
* @see #setServerClasses(String[])
* @see http://www.eclipse.org/jetty/documentation/current/jetty-classloading.html
* @param classOrPackage A fully qualified class name (eg com.foo.MyClass)
* or a qualified package name ending with '.' (eg com.foo.). If the class
* or package has '-' it is excluded from the server classes and order is thus
@ -703,6 +705,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
/* ------------------------------------------------------------ */
/** Add to the list of System classes.
* @see http://www.eclipse.org/jetty/documentation/current/jetty-classloading.html
* @see #setSystemClasses(String[])
* @param classOrPackage A fully qualified class name (eg com.foo.MyClass)
* or a qualified package name ending with '.' (eg com.foo.). If the class
@ -722,6 +725,7 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
/* ------------------------------------------------------------ */
/** Prepend to the list of System classes.
* @see #setSystemClasses(String[])
* @see http://www.eclipse.org/jetty/documentation/current/jetty-classloading.html
* @param classOrPackage A fully qualified class name (eg com.foo.MyClass)
* or a qualified package name ending with '.' (eg com.foo.). If the class
* or package has '-' it is excluded from the system classes and order is thus
@ -872,7 +876,8 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
* @return True if the classloader should delegate first to the parent
* classloader (standard java behaviour) or false if the classloader
* should first try to load from WEB-INF/lib or WEB-INF/classes (servlet
* spec recommendation).
* spec recommendation). Default is false or can be set by the system
* property org.eclipse.jetty.server.webapp.parentLoaderPriority
*/
@Override
@ManagedAttribute(value="parent classloader given priority", readonly=true)
@ -1104,7 +1109,11 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL
/* ------------------------------------------------------------ */
/**
* @param java2compliant The java2compliant to set.
* @param java2compliant True if the classloader should delegate first to the parent
* classloader (standard java behaviour) or false if the classloader
* should first try to load from WEB-INF/lib or WEB-INF/classes (servlet
* spec recommendation). Default is false or can be set by the system
* property org.eclipse.jetty.server.webapp.parentLoaderPriority
*/
public void setParentLoaderPriority(boolean java2compliant)
{

View File

@ -496,7 +496,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
@Override
protected boolean onReadTimeout()
{
LOG.warn("Read Timeout");
LOG.info("Read Timeout");
IOState state = getIOState();
if ((state.getState() == ConnectionState.CLOSING) || (state.getState() == ConnectionState.CLOSED))

View File

@ -265,7 +265,7 @@
<plugin>
<groupId>org.eclipse.jetty.toolchain</groupId>
<artifactId>jetty-version-maven-plugin</artifactId>
<version>1.0.9</version>
<version>1.0.10</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>