summaryrefslogtreecommitdiff
path: root/java/common
diff options
context:
space:
mode:
authorStephen D. Huston <shuston@apache.org>2011-10-21 01:19:00 +0000
committerStephen D. Huston <shuston@apache.org>2011-10-21 01:19:00 +0000
commitebfd9ff053b04ab379acfc0fefedee5a31b6d8a5 (patch)
treedcfb94e75656c6c239fc3dcb754cd2015126424d /java/common
parent5eb354b338bb8d8fcd35b6ac3fb33f8103e757c3 (diff)
downloadqpid-python-ebfd9ff053b04ab379acfc0fefedee5a31b6d8a5.tar.gz
Undo bad merge from trunk - merged at wrong level.
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/QPID-2519@1187150 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java/common')
-rwxr-xr-xjava/common/bin/qpid-run13
-rwxr-xr-xjava/common/src/main/java/common.bnd2
-rw-r--r--java/common/src/main/java/org/apache/mina/common/FixedSizeByteBufferAllocator.java467
-rw-r--r--java/common/src/main/java/org/apache/mina/common/support/DefaultIoFuture.java227
-rw-r--r--java/common/src/main/java/org/apache/mina/common/support/IoServiceListenerSupport.java351
-rw-r--r--java/common/src/main/java/org/apache/mina/filter/WriteBufferFullExeception.java (renamed from java/common/src/main/java/org/apache/qpid/transport/SenderClosedException.java)32
-rw-r--r--java/common/src/main/java/org/apache/mina/filter/WriteBufferLimitFilterBuilder.java272
-rw-r--r--java/common/src/main/java/org/apache/mina/filter/codec/OurCumulativeProtocolDecoder.java197
-rw-r--r--java/common/src/main/java/org/apache/mina/filter/codec/QpidProtocolCodecFilter.java440
-rw-r--r--java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketAcceptor.java547
-rw-r--r--java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketConnector.java486
-rw-r--r--java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketFilterChain.java67
-rw-r--r--java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketIoProcessor.java1026
-rw-r--r--java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketSessionConfigImpl.java240
-rw-r--r--java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketSessionImpl.java488
-rw-r--r--java/common/src/main/java/org/apache/mina/transport/vmpipe/QpidVmPipeConnector.java151
-rw-r--r--java/common/src/main/java/org/apache/qpid/AMQChannelException.java3
-rw-r--r--java/common/src/main/java/org/apache/qpid/AMQConnectionException.java3
-rw-r--r--java/common/src/main/java/org/apache/qpid/AMQException.java16
-rw-r--r--java/common/src/main/java/org/apache/qpid/AMQInvalidArgumentException.java2
-rw-r--r--java/common/src/main/java/org/apache/qpid/ToyBroker.java208
-rw-r--r--java/common/src/main/java/org/apache/qpid/ToyClient.java108
-rw-r--r--java/common/src/main/java/org/apache/qpid/ToyExchange.java154
-rw-r--r--java/common/src/main/java/org/apache/qpid/codec/AMQCodecFactory.java17
-rw-r--r--java/common/src/main/java/org/apache/qpid/codec/AMQDecoder.java334
-rw-r--r--java/common/src/main/java/org/apache/qpid/codec/AMQEncoder.java66
-rw-r--r--java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java59
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQBody.java8
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQDataBlock.java26
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java57
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockEncoder.java61
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQFrame.java42
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQMethodBody.java8
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyFactory.java7
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyImpl.java86
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyInstanceFactory.java5
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQMethodFactory.java90
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java115
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQType.java81
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java13
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java374
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/BodyFactory.java5
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/CompositeAMQDataBlock.java5
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/ContentBody.java59
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/ContentBodyFactory.java5
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBody.java58
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBodyFactory.java5
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/ContentHeaderProperties.java12
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/ContentHeaderPropertiesFactory.java7
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/DeferredDataBlock.java50
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/EncodingUtils.java229
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/FieldTable.java215
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/FieldTableFactory.java5
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/HeartbeatBody.java15
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/HeartbeatBodyFactory.java4
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/ProtocolInitiation.java37
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/SmallCompositeAMQDataBlock.java5
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/VersionSpecificRegistry.java5
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/abstraction/ContentChunk.java4
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/abstraction/ProtocolVersionMethodConverter.java4
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/MethodConverter_0_9.java13
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/amqp_0_91/MethodConverter_0_91.java10
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/MethodConverter_8_0.java11
-rw-r--r--java/common/src/main/java/org/apache/qpid/pool/Job.java253
-rw-r--r--java/common/src/main/java/org/apache/qpid/protocol/AMQConstant.java9
-rw-r--r--java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngine.java10
-rw-r--r--java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngineFactory.java4
-rw-r--r--java/common/src/main/java/org/apache/qpid/security/AMQPCallbackHandler.java (renamed from java/common/src/main/java/org/apache/qpid/protocol/ServerProtocolEngine.java)15
-rw-r--r--java/common/src/main/java/org/apache/qpid/security/UsernamePasswordCallbackHandler.java60
-rw-r--r--java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java216
-rw-r--r--java/common/src/main/java/org/apache/qpid/thread/QpidThreadExecutor.java2
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java145
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Connection.java114
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ConnectionDelegate.java3
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java4
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/NetworkDriver.java63
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/NetworkDriverConfiguration.java (renamed from java/common/src/main/java/org/apache/qpid/transport/NetworkTransportConfiguration.java)20
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java69
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Session.java184
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/SessionDelegate.java16
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/TransportBuilder.java78
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/codec/AbstractEncoder.java1
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/IncomingNetworkTransport.java31
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/NetworkConnection.java49
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/NetworkTransport.java18
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/OutgoingNetworkTransport.java35
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/Transport.java122
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/InputHandler_0_9.java130
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/IoAcceptor.java (renamed from java/common/src/test/java/org/apache/qpid/transport/network/io/IoAcceptor.java)2
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/IoContext.java (renamed from java/common/src/test/java/org/apache/qpid/transport/MockSender.java)38
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkConnection.java99
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java223
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java49
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/IoSender.java68
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/IoTransport.java231
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java435
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaHandler.java274
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaSender.java90
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/nio/NioHandler.java135
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/nio/NioSender.java126
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/security/SSLStatus.java49
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayer.java153
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayerFactory.java161
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/security/sasl/SASLSender.java6
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/QpidClientX509KeyManager.java16
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLReceiver.java63
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLSender.java56
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java37
-rw-r--r--java/common/src/main/java/org/apache/qpid/url/URLHelper.java3
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/FileUtils.java25
-rw-r--r--java/common/src/test/java/org/apache/mina/SocketIOTest/IOWriterClient.java396
-rw-r--r--java/common/src/test/java/org/apache/mina/SocketIOTest/IOWriterServer.java157
-rw-r--r--java/common/src/test/java/org/apache/qpid/AMQExceptionTest.java13
-rw-r--r--java/common/src/test/java/org/apache/qpid/codec/AMQDecoderTest.java32
-rw-r--r--java/common/src/test/java/org/apache/qpid/framing/AMQShortStringTest.java214
-rw-r--r--java/common/src/test/java/org/apache/qpid/framing/BasicContentHeaderPropertiesTest.java11
-rw-r--r--java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java30
-rw-r--r--java/common/src/test/java/org/apache/qpid/session/TestSession.java277
-rw-r--r--java/common/src/test/java/org/apache/qpid/ssl/SSLContextFactoryTest.java84
-rw-r--r--java/common/src/test/java/org/apache/qpid/test/utils/QpidTestCase.java206
-rw-r--r--java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java107
-rw-r--r--java/common/src/test/java/org/apache/qpid/transport/SessionTimeoutTest.java81
-rw-r--r--java/common/src/test/java/org/apache/qpid/transport/TestNetworkDriver.java (renamed from java/common/src/test/java/org/apache/qpid/transport/TestNetworkConnection.java)41
-rw-r--r--java/common/src/test/java/org/apache/qpid/transport/network/TransportTest.java157
-rw-r--r--java/common/src/test/java/org/apache/qpid/transport/network/io/IoTransport.java91
-rw-r--r--java/common/src/test/java/org/apache/qpid/transport/network/mina/MINANetworkDriverTest.java494
-rw-r--r--java/common/src/test/java/org/apache/qpid/util/FileUtilsTest.java82
-rw-r--r--java/common/src/test/java/org/apache/qpid/util/default.properties2
-rw-r--r--java/common/src/test/java/org/apache/qpid/util/mydefaults.properties2
-rw-r--r--java/common/templates/method/version/MethodBodyClass.vm10
-rw-r--r--java/common/templates/model/MethodRegistryClass.vm9
-rw-r--r--java/common/templates/model/version/MethodRegistryClass.vm95
132 files changed, 11110 insertions, 3183 deletions
diff --git a/java/common/bin/qpid-run b/java/common/bin/qpid-run
index ef4363e88b..15d88992df 100755
--- a/java/common/bin/qpid-run
+++ b/java/common/bin/qpid-run
@@ -77,10 +77,7 @@ fi
#Set the default system properties that we'll use now that they have
#all been initialised
-declare -a SYSTEM_PROPS
-SYSTEM_PROPS[${#SYSTEM_PROPS[@]}]="-Damqj.logging.level=$AMQJ_LOGGING_LEVEL"
-SYSTEM_PROPS[${#SYSTEM_PROPS[@]}]="-DQPID_HOME=$QPID_HOME"
-SYSTEM_PROPS[${#SYSTEM_PROPS[@]}]="-DQPID_WORK=$QPID_WORK"
+SYSTEM_PROPS="-Damqj.logging.level=$AMQJ_LOGGING_LEVEL -DQPID_HOME=$QPID_HOME -DQPID_WORK=$QPID_WORK"
#If logprefix or logsuffix set to use PID make that happen
#Otherwise just pass the value through for these props
@@ -93,7 +90,7 @@ if [ -n "$QPID_LOG_PREFIX" ]; then
log $INFO Using qpid logprefix property
LOG_PREFIX=" -Dlogprefix=$QPID_LOG_PREFIX"
fi
- SYSTEM_PROPS[${#SYSTEM_PROPS[@]}]="${LOG_PREFIX}"
+ SYSTEM_PROPS="${SYSTEM_PROPS} ${LOG_PREFIX}"
fi
if [ -n "$QPID_LOG_SUFFIX" ]; then
@@ -104,10 +101,10 @@ if [ -n "$QPID_LOG_SUFFIX" ]; then
log $INFO Using qpig logsuffix property
LOG_SUFFIX=" -Dlogsuffix=$QPID_LOG_SUFFIX"
fi
- SYSTEM_PROPS[${#SYSTEM_PROPS[@]}]="${LOG_SUFFIX}"
+ SYSTEM_PROPS="${SYSTEM_PROPS} ${LOG_SUFFIX}"
fi
-log $INFO System Properties set to ${SYSTEM_PROPS[@]}
+log $INFO System Properties set to $SYSTEM_PROPS
log $INFO QPID_OPTS set to $QPID_OPTS
program=$(basename $0)
@@ -257,6 +254,6 @@ if $cygwin; then
JAVA=$(cygpath -u $JAVA)
fi
-COMMAND=($JAVA $JAVA_VM $QPID_PNAME $JAVA_GC $JAVA_MEM "${SYSTEM_PROPS[@]}" $JAVA_OPTS $QPID_OPTS "${JAVA_ARGS[@]}")
+COMMAND=($JAVA $JAVA_VM $QPID_PNAME $JAVA_GC $JAVA_MEM $SYSTEM_PROPS $JAVA_OPTS $QPID_OPTS "${JAVA_ARGS[@]}")
DISPATCH
diff --git a/java/common/src/main/java/common.bnd b/java/common/src/main/java/common.bnd
index f12fbf9273..ef56ecec9e 100755
--- a/java/common/src/main/java/common.bnd
+++ b/java/common/src/main/java/common.bnd
@@ -17,7 +17,7 @@
# under the License.
#
-ver: 0.13.0
+ver: 0.9.0
Bundle-SymbolicName: qpid-common
Bundle-Version: ${ver}
diff --git a/java/common/src/main/java/org/apache/mina/common/FixedSizeByteBufferAllocator.java b/java/common/src/main/java/org/apache/mina/common/FixedSizeByteBufferAllocator.java
new file mode 100644
index 0000000000..0c311b6645
--- /dev/null
+++ b/java/common/src/main/java/org/apache/mina/common/FixedSizeByteBufferAllocator.java
@@ -0,0 +1,467 @@
+package org.apache.mina.common;
+
+import org.apache.mina.common.ByteBuffer;
+
+import java.nio.*;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+public class FixedSizeByteBufferAllocator implements ByteBufferAllocator
+{
+
+
+ private static final int MINIMUM_CAPACITY = 1;
+
+ public FixedSizeByteBufferAllocator ()
+ {
+ }
+
+ public ByteBuffer allocate( int capacity, boolean direct )
+ {
+ java.nio.ByteBuffer nioBuffer;
+ if( direct )
+ {
+ nioBuffer = java.nio.ByteBuffer.allocateDirect( capacity );
+ }
+ else
+ {
+ nioBuffer = java.nio.ByteBuffer.allocate( capacity );
+ }
+ return new FixedSizeByteBuffer( nioBuffer );
+ }
+
+ public ByteBuffer wrap( java.nio.ByteBuffer nioBuffer )
+ {
+ return new FixedSizeByteBuffer( nioBuffer );
+ }
+
+ public void dispose()
+ {
+ }
+
+
+
+ private static final class FixedSizeByteBuffer extends ByteBuffer
+ {
+ private java.nio.ByteBuffer buf;
+ private int mark = -1;
+
+
+ protected FixedSizeByteBuffer( java.nio.ByteBuffer buf )
+ {
+ this.buf = buf;
+ buf.order( ByteOrder.BIG_ENDIAN );
+ }
+
+ public synchronized void acquire()
+ {
+ }
+
+ public void release()
+ {
+ }
+
+ public java.nio.ByteBuffer buf()
+ {
+ return buf;
+ }
+
+ public boolean isPooled()
+ {
+ return false;
+ }
+
+ public void setPooled( boolean pooled )
+ {
+ }
+
+ public ByteBuffer duplicate() {
+ return new FixedSizeByteBuffer( this.buf.duplicate() );
+ }
+
+ public ByteBuffer slice() {
+ return new FixedSizeByteBuffer( this.buf.slice() );
+ }
+
+ public ByteBuffer asReadOnlyBuffer() {
+ return new FixedSizeByteBuffer( this.buf.asReadOnlyBuffer() );
+ }
+
+ public byte[] array()
+ {
+ return buf.array();
+ }
+
+ public int arrayOffset()
+ {
+ return buf.arrayOffset();
+ }
+
+ public boolean isDirect()
+ {
+ return buf.isDirect();
+ }
+
+ public boolean isReadOnly()
+ {
+ return buf.isReadOnly();
+ }
+
+ public int capacity()
+ {
+ return buf.capacity();
+ }
+
+ public ByteBuffer capacity( int newCapacity )
+ {
+ if( newCapacity > capacity() )
+ {
+ throw new IllegalArgumentException();
+ }
+
+ return this;
+ }
+
+
+
+ public boolean isAutoExpand()
+ {
+ return false;
+ }
+
+ public ByteBuffer setAutoExpand( boolean autoExpand )
+ {
+ if(autoExpand) throw new IllegalArgumentException();
+ else return this;
+ }
+
+ public ByteBuffer expand( int pos, int expectedRemaining )
+ {
+ int end = pos + expectedRemaining;
+ if( end > capacity() )
+ {
+ // The buffer needs expansion.
+ capacity( end );
+ }
+
+ if( end > limit() )
+ {
+ // We call limit() directly to prevent StackOverflowError
+ buf.limit( end );
+ }
+ return this;
+ }
+
+ public int position()
+ {
+ return buf.position();
+ }
+
+ public ByteBuffer position( int newPosition )
+ {
+
+ buf.position( newPosition );
+ if( mark > newPosition )
+ {
+ mark = -1;
+ }
+ return this;
+ }
+
+ public int limit()
+ {
+ return buf.limit();
+ }
+
+ public ByteBuffer limit( int newLimit )
+ {
+ buf.limit( newLimit );
+ if( mark > newLimit )
+ {
+ mark = -1;
+ }
+ return this;
+ }
+
+ public ByteBuffer mark()
+ {
+ buf.mark();
+ mark = position();
+ return this;
+ }
+
+ public int markValue()
+ {
+ return mark;
+ }
+
+ public ByteBuffer reset()
+ {
+ buf.reset();
+ return this;
+ }
+
+ public ByteBuffer clear()
+ {
+ buf.clear();
+ mark = -1;
+ return this;
+ }
+
+ public ByteBuffer flip()
+ {
+ buf.flip();
+ mark = -1;
+ return this;
+ }
+
+ public ByteBuffer rewind()
+ {
+ buf.rewind();
+ mark = -1;
+ return this;
+ }
+
+ public byte get()
+ {
+ return buf.get();
+ }
+
+ public ByteBuffer put( byte b )
+ {
+ buf.put( b );
+ return this;
+ }
+
+ public byte get( int index )
+ {
+ return buf.get( index );
+ }
+
+ public ByteBuffer put( int index, byte b )
+ {
+ buf.put( index, b );
+ return this;
+ }
+
+ public ByteBuffer get( byte[] dst, int offset, int length )
+ {
+ buf.get( dst, offset, length );
+ return this;
+ }
+
+ public ByteBuffer put( java.nio.ByteBuffer src )
+ {
+ buf.put( src );
+ return this;
+ }
+
+ public ByteBuffer put( byte[] src, int offset, int length )
+ {
+ buf.put( src, offset, length );
+ return this;
+ }
+
+ public ByteBuffer compact()
+ {
+ buf.compact();
+ mark = -1;
+ return this;
+ }
+
+ public ByteOrder order()
+ {
+ return buf.order();
+ }
+
+ public ByteBuffer order( ByteOrder bo )
+ {
+ buf.order( bo );
+ return this;
+ }
+
+ public char getChar()
+ {
+ return buf.getChar();
+ }
+
+ public ByteBuffer putChar( char value )
+ {
+ buf.putChar( value );
+ return this;
+ }
+
+ public char getChar( int index )
+ {
+ return buf.getChar( index );
+ }
+
+ public ByteBuffer putChar( int index, char value )
+ {
+ buf.putChar( index, value );
+ return this;
+ }
+
+ public CharBuffer asCharBuffer()
+ {
+ return buf.asCharBuffer();
+ }
+
+ public short getShort()
+ {
+ return buf.getShort();
+ }
+
+ public ByteBuffer putShort( short value )
+ {
+ buf.putShort( value );
+ return this;
+ }
+
+ public short getShort( int index )
+ {
+ return buf.getShort( index );
+ }
+
+ public ByteBuffer putShort( int index, short value )
+ {
+ buf.putShort( index, value );
+ return this;
+ }
+
+ public ShortBuffer asShortBuffer()
+ {
+ return buf.asShortBuffer();
+ }
+
+ public int getInt()
+ {
+ return buf.getInt();
+ }
+
+ public ByteBuffer putInt( int value )
+ {
+ buf.putInt( value );
+ return this;
+ }
+
+ public int getInt( int index )
+ {
+ return buf.getInt( index );
+ }
+
+ public ByteBuffer putInt( int index, int value )
+ {
+ buf.putInt( index, value );
+ return this;
+ }
+
+ public IntBuffer asIntBuffer()
+ {
+ return buf.asIntBuffer();
+ }
+
+ public long getLong()
+ {
+ return buf.getLong();
+ }
+
+ public ByteBuffer putLong( long value )
+ {
+ buf.putLong( value );
+ return this;
+ }
+
+ public long getLong( int index )
+ {
+ return buf.getLong( index );
+ }
+
+ public ByteBuffer putLong( int index, long value )
+ {
+ buf.putLong( index, value );
+ return this;
+ }
+
+ public LongBuffer asLongBuffer()
+ {
+ return buf.asLongBuffer();
+ }
+
+ public float getFloat()
+ {
+ return buf.getFloat();
+ }
+
+ public ByteBuffer putFloat( float value )
+ {
+ buf.putFloat( value );
+ return this;
+ }
+
+ public float getFloat( int index )
+ {
+ return buf.getFloat( index );
+ }
+
+ public ByteBuffer putFloat( int index, float value )
+ {
+ buf.putFloat( index, value );
+ return this;
+ }
+
+ public FloatBuffer asFloatBuffer()
+ {
+ return buf.asFloatBuffer();
+ }
+
+ public double getDouble()
+ {
+ return buf.getDouble();
+ }
+
+ public ByteBuffer putDouble( double value )
+ {
+ buf.putDouble( value );
+ return this;
+ }
+
+ public double getDouble( int index )
+ {
+ return buf.getDouble( index );
+ }
+
+ public ByteBuffer putDouble( int index, double value )
+ {
+ buf.putDouble( index, value );
+ return this;
+ }
+
+ public DoubleBuffer asDoubleBuffer()
+ {
+ return buf.asDoubleBuffer();
+ }
+
+
+ }
+
+
+}
diff --git a/java/common/src/main/java/org/apache/mina/common/support/DefaultIoFuture.java b/java/common/src/main/java/org/apache/mina/common/support/DefaultIoFuture.java
new file mode 100644
index 0000000000..4fd28c4eb5
--- /dev/null
+++ b/java/common/src/main/java/org/apache/mina/common/support/DefaultIoFuture.java
@@ -0,0 +1,227 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.mina.common.support;
+
+import org.apache.mina.common.IoFuture;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.common.IoFutureListener;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Iterator;
+
+/**
+ * A default implementation of {@link org.apache.mina.common.IoFuture}.
+ *
+ * @author The Apache Directory Project (mina-dev@directory.apache.org)
+ */
+public class DefaultIoFuture implements IoFuture
+{
+ private final IoSession session;
+ private final Object lock;
+ private List listeners;
+ private Object result;
+ private boolean ready;
+
+
+ /**
+ * Creates a new instance.
+ *
+ * @param session an {@link IoSession} which is associated with this future
+ */
+ public DefaultIoFuture( IoSession session )
+ {
+ this.session = session;
+ this.lock = this;
+ }
+
+ /**
+ * Creates a new instance which uses the specified object as a lock.
+ */
+ public DefaultIoFuture( IoSession session, Object lock )
+ {
+ if( lock == null )
+ {
+ throw new NullPointerException( "lock" );
+ }
+ this.session = session;
+ this.lock = lock;
+ }
+
+ public IoSession getSession()
+ {
+ return session;
+ }
+
+ public Object getLock()
+ {
+ return lock;
+ }
+
+ public void join()
+ {
+ synchronized( lock )
+ {
+ while( !ready )
+ {
+ try
+ {
+ lock.wait();
+ }
+ catch( InterruptedException e )
+ {
+ }
+ }
+ }
+ }
+
+ public boolean join( long timeoutInMillis )
+ {
+ long startTime = ( timeoutInMillis <= 0 ) ? 0 : System
+ .currentTimeMillis();
+ long waitTime = timeoutInMillis;
+
+ synchronized( lock )
+ {
+ if( ready )
+ {
+ return ready;
+ }
+ else if( waitTime <= 0 )
+ {
+ return ready;
+ }
+
+ for( ;; )
+ {
+ try
+ {
+ lock.wait( waitTime );
+ }
+ catch( InterruptedException e )
+ {
+ }
+
+ if( ready )
+ return true;
+ else
+ {
+ waitTime = timeoutInMillis - ( System.currentTimeMillis() - startTime );
+ if( waitTime <= 0 )
+ {
+ return ready;
+ }
+ }
+ }
+ }
+ }
+
+ public boolean isReady()
+ {
+ synchronized( lock )
+ {
+ return ready;
+ }
+ }
+
+ /**
+ * Sets the result of the asynchronous operation, and mark it as finished.
+ */
+ protected void setValue( Object newValue )
+ {
+ synchronized( lock )
+ {
+ // Allow only once.
+ if( ready )
+ {
+ return;
+ }
+
+ result = newValue;
+ ready = true;
+ lock.notifyAll();
+
+ notifyListeners();
+ }
+ }
+
+ /**
+ * Returns the result of the asynchronous operation.
+ */
+ protected Object getValue()
+ {
+ synchronized( lock )
+ {
+ return result;
+ }
+ }
+
+ public void addListener( IoFutureListener listener )
+ {
+ if( listener == null )
+ {
+ throw new NullPointerException( "listener" );
+ }
+
+ synchronized( lock )
+ {
+ if(listeners == null)
+ {
+ listeners = new ArrayList();
+ }
+ listeners.add( listener );
+ if( ready )
+ {
+ listener.operationComplete( this );
+ }
+ }
+ }
+
+ public void removeListener( IoFutureListener listener )
+ {
+ if( listener == null )
+ {
+ throw new NullPointerException( "listener" );
+ }
+
+ synchronized( lock )
+ {
+ listeners.remove( listener );
+ }
+ }
+
+ private void notifyListeners()
+ {
+ synchronized( lock )
+ {
+
+ if(listeners != null)
+ {
+
+ for( Iterator i = listeners.iterator(); i.hasNext(); ) {
+ ( ( IoFutureListener ) i.next() ).operationComplete( this );
+ }
+ }
+ }
+ }
+}
+
+
+
diff --git a/java/common/src/main/java/org/apache/mina/common/support/IoServiceListenerSupport.java b/java/common/src/main/java/org/apache/mina/common/support/IoServiceListenerSupport.java
new file mode 100644
index 0000000000..5723ffbaa9
--- /dev/null
+++ b/java/common/src/main/java/org/apache/mina/common/support/IoServiceListenerSupport.java
@@ -0,0 +1,351 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.mina.common.support;
+
+import java.net.SocketAddress;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+
+import org.apache.mina.common.IoAcceptorConfig;
+import org.apache.mina.common.IoConnector;
+import org.apache.mina.common.IoFuture;
+import org.apache.mina.common.IoFutureListener;
+import org.apache.mina.common.IoHandler;
+import org.apache.mina.common.IoService;
+import org.apache.mina.common.IoServiceConfig;
+import org.apache.mina.common.IoServiceListener;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.util.IdentityHashSet;
+
+/**
+ * A helper which provides addition and removal of {@link IoServiceListener}s and firing
+ * events.
+ *
+ * @author The Apache Directory Project (mina-dev@directory.apache.org)
+ * @version $Rev: 446526 $, $Date: 2006-09-15 01:44:11 -0400 (Fri, 15 Sep 2006) $
+ */
+public class IoServiceListenerSupport
+{
+ /**
+ * A list of {@link IoServiceListener}s.
+ */
+ private final List listeners = new ArrayList();
+
+ /**
+ * Tracks managed <tt>serviceAddress</tt>es.
+ */
+ private final Set managedServiceAddresses = new HashSet();
+
+ /**
+ * Tracks managed sesssions with <tt>serviceAddress</tt> as a key.
+ */
+ private final Map managedSessions = new HashMap();
+
+ /**
+ * Creates a new instance.
+ */
+ public IoServiceListenerSupport()
+ {
+ }
+
+ /**
+ * Adds a new listener.
+ */
+ public void add( IoServiceListener listener )
+ {
+ synchronized( listeners )
+ {
+ listeners.add( listener );
+ }
+ }
+
+ /**
+ * Removes an existing listener.
+ */
+ public void remove( IoServiceListener listener )
+ {
+ synchronized( listeners )
+ {
+ listeners.remove( listener );
+ }
+ }
+
+ public Set getManagedServiceAddresses()
+ {
+ return Collections.unmodifiableSet( managedServiceAddresses );
+ }
+
+ public boolean isManaged( SocketAddress serviceAddress )
+ {
+ synchronized( managedServiceAddresses )
+ {
+ return managedServiceAddresses.contains( serviceAddress );
+ }
+ }
+
+ public Set getManagedSessions( SocketAddress serviceAddress )
+ {
+ Set sessions;
+ synchronized( managedSessions )
+ {
+ sessions = ( Set ) managedSessions.get( serviceAddress );
+ if( sessions == null )
+ {
+ sessions = new IdentityHashSet();
+ }
+ }
+
+ synchronized( sessions )
+ {
+ return new IdentityHashSet( sessions );
+ }
+ }
+
+ /**
+ * Calls {@link IoServiceListener#serviceActivated(IoService, SocketAddress, IoHandler, IoServiceConfig)}
+ * for all registered listeners.
+ */
+ public void fireServiceActivated(
+ IoService service, SocketAddress serviceAddress,
+ IoHandler handler, IoServiceConfig config )
+ {
+ synchronized( managedServiceAddresses )
+ {
+ if( !managedServiceAddresses.add( serviceAddress ) )
+ {
+ return;
+ }
+ }
+
+ synchronized( listeners )
+ {
+ for( Iterator i = listeners.iterator(); i.hasNext(); )
+ {
+ ( ( IoServiceListener ) i.next() ).serviceActivated(
+ service, serviceAddress, handler, config );
+ }
+ }
+ }
+
+ /**
+ * Calls {@link IoServiceListener#serviceDeactivated(IoService, SocketAddress, IoHandler, IoServiceConfig)}
+ * for all registered listeners.
+ */
+ public synchronized void fireServiceDeactivated(
+ IoService service, SocketAddress serviceAddress,
+ IoHandler handler, IoServiceConfig config )
+ {
+ synchronized( managedServiceAddresses )
+ {
+ if( !managedServiceAddresses.remove( serviceAddress ) )
+ {
+ return;
+ }
+ }
+
+ try
+ {
+ synchronized( listeners )
+ {
+ for( Iterator i = listeners.iterator(); i.hasNext(); )
+ {
+ ( ( IoServiceListener ) i.next() ).serviceDeactivated(
+ service, serviceAddress, handler, config );
+ }
+ }
+ }
+ finally
+ {
+ disconnectSessions( serviceAddress, config );
+ }
+ }
+
+
+ /**
+ * Calls {@link IoServiceListener#sessionCreated(IoSession)} for all registered listeners.
+ */
+ public void fireSessionCreated( IoSession session )
+ {
+ SocketAddress serviceAddress = session.getServiceAddress();
+
+ // Get the session set.
+ boolean firstSession = false;
+ Set sessions;
+ synchronized( managedSessions )
+ {
+ sessions = ( Set ) managedSessions.get( serviceAddress );
+ if( sessions == null )
+ {
+ sessions = new IdentityHashSet();
+ managedSessions.put( serviceAddress, sessions );
+ firstSession = true;
+ }
+ }
+
+ // If already registered, ignore.
+ synchronized( sessions )
+ {
+ if ( !sessions.add( session ) )
+ {
+ return;
+ }
+ }
+
+ // If the first connector session, fire a virtual service activation event.
+ if( session.getService() instanceof IoConnector && firstSession )
+ {
+ fireServiceActivated(
+ session.getService(), session.getServiceAddress(),
+ session.getHandler(), session.getServiceConfig() );
+ }
+
+ // Fire session events.
+ session.getFilterChain().fireSessionCreated( session );
+ session.getFilterChain().fireSessionOpened( session);
+
+ // Fire listener events.
+ synchronized( listeners )
+ {
+ for( Iterator i = listeners.iterator(); i.hasNext(); )
+ {
+ ( ( IoServiceListener ) i.next() ).sessionCreated( session );
+ }
+ }
+ }
+
+ /**
+ * Calls {@link IoServiceListener#sessionDestroyed(IoSession)} for all registered listeners.
+ */
+ public void fireSessionDestroyed( IoSession session )
+ {
+ SocketAddress serviceAddress = session.getServiceAddress();
+
+ // Get the session set.
+ Set sessions;
+ boolean lastSession = false;
+ synchronized( managedSessions )
+ {
+ sessions = ( Set ) managedSessions.get( serviceAddress );
+ // Ignore if unknown.
+ if( sessions == null )
+ {
+ return;
+ }
+
+ // Try to remove the remaining empty seession set after removal.
+ synchronized( sessions )
+ {
+ sessions.remove( session );
+ if( sessions.isEmpty() )
+ {
+ managedSessions.remove( serviceAddress );
+ lastSession = true;
+ }
+ }
+ }
+
+ // Fire session events.
+ session.getFilterChain().fireSessionClosed( session );
+
+ // Fire listener events.
+ try
+ {
+ synchronized( listeners )
+ {
+ for( Iterator i = listeners.iterator(); i.hasNext(); )
+ {
+ ( ( IoServiceListener ) i.next() ).sessionDestroyed( session );
+ }
+ }
+ }
+ finally
+ {
+ // Fire a virtual service deactivation event for the last session of the connector.
+ //TODO double-check that this is *STILL* the last session. May not be the case
+ if( session.getService() instanceof IoConnector && lastSession )
+ {
+ fireServiceDeactivated(
+ session.getService(), session.getServiceAddress(),
+ session.getHandler(), session.getServiceConfig() );
+ }
+ }
+ }
+
+ private void disconnectSessions( SocketAddress serviceAddress, IoServiceConfig config )
+ {
+ if( !( config instanceof IoAcceptorConfig ) )
+ {
+ return;
+ }
+
+ if( !( ( IoAcceptorConfig ) config ).isDisconnectOnUnbind() )
+ {
+ return;
+ }
+
+ Set sessions;
+ synchronized( managedSessions )
+ {
+ sessions = ( Set ) managedSessions.get( serviceAddress );
+ }
+
+ if( sessions == null )
+ {
+ return;
+ }
+
+ Set sessionsCopy;
+
+ // Create a copy to avoid ConcurrentModificationException
+ synchronized( sessions )
+ {
+ sessionsCopy = new IdentityHashSet( sessions );
+ }
+
+ final CountDownLatch latch = new CountDownLatch(sessionsCopy.size());
+
+ for( Iterator i = sessionsCopy.iterator(); i.hasNext(); )
+ {
+ ( ( IoSession ) i.next() ).close().addListener( new IoFutureListener()
+ {
+ public void operationComplete( IoFuture future )
+ {
+ latch.countDown();
+ }
+ } );
+ }
+
+ try
+ {
+ latch.await();
+ }
+ catch( InterruptedException ie )
+ {
+ // Ignored
+ }
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/SenderClosedException.java b/java/common/src/main/java/org/apache/mina/filter/WriteBufferFullExeception.java
index 924c327861..47f19aa76d 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/SenderClosedException.java
+++ b/java/common/src/main/java/org/apache/mina/filter/WriteBufferFullExeception.java
@@ -1,4 +1,6 @@
-/*
+package org.apache.mina.filter;
+
+import org.apache.mina.common.IoFilter;/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
@@ -18,35 +20,29 @@
* under the License.
*
*/
-package org.apache.qpid.transport;
-
-/**
- * SenderClosedException
- *
- */
-
-public class SenderClosedException extends SenderException
+public class WriteBufferFullExeception extends RuntimeException
{
+ private IoFilter.WriteRequest _writeRequest;
- public SenderClosedException(String message, Throwable cause)
+ public WriteBufferFullExeception()
{
- super(message, cause);
+ this(null);
}
- public SenderClosedException(String message)
+ public WriteBufferFullExeception(IoFilter.WriteRequest writeRequest)
{
- super(message);
+ _writeRequest = writeRequest;
}
- public SenderClosedException(Throwable cause)
+
+ public void setWriteRequest(IoFilter.WriteRequest writeRequest)
{
- super(cause);
+ _writeRequest = writeRequest;
}
- public void rethrow()
+ public IoFilter.WriteRequest getWriteRequest()
{
- throw new SenderClosedException(getMessage(), this);
+ return _writeRequest;
}
-
}
diff --git a/java/common/src/main/java/org/apache/mina/filter/WriteBufferLimitFilterBuilder.java b/java/common/src/main/java/org/apache/mina/filter/WriteBufferLimitFilterBuilder.java
new file mode 100644
index 0000000000..4e9db9071a
--- /dev/null
+++ b/java/common/src/main/java/org/apache/mina/filter/WriteBufferLimitFilterBuilder.java
@@ -0,0 +1,272 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.mina.filter;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.DefaultIoFilterChainBuilder;
+import org.apache.mina.common.IoFilterAdapter;
+import org.apache.mina.common.IoFilterChain;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.filter.executor.ExecutorFilter;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This filter will turn the asynchronous filterWrite method in to a blocking send when there are more than
+ * the prescribed number of messages awaiting filterWrite. It should be used in conjunction with the
+ * {@link ReadThrottleFilterBuilder} on a server as the blocking writes will allow the read thread to
+ * cause an Out of Memory exception due to a back log of unprocessed messages.
+ *
+ * This is should only be viewed as a temporary work around for DIRMINA-302.
+ *
+ * A true solution should not be implemented as a filter as this issue will always occur. On a machine
+ * where the network is slower than the local producer.
+ *
+ * Suggested improvement is to allow implementation of policices on what to do when buffer is full.
+ *
+ * They could be:
+ * Block - As this does
+ * Wait on a given Future - to drain more of the queue.. in essence this filter with high/low watermarks
+ * Throw Exception - through the client filterWrite() method to allow them to get immediate feedback on buffer state
+ *
+ * <p/>
+ * <p>Usage:
+ * <p/>
+ * <pre><code>
+ * DefaultFilterChainBuilder builder = ...
+ * WriteBufferLimitFilterBuilder filter = new WriteBufferLimitFilterBuilder();
+ * filter.attach( builder );
+ * </code></pre>
+ * <p/>
+ * or
+ * <p/>
+ * <pre><code>
+ * IoFilterChain chain = ...
+ * WriteBufferLimitFilterBuilder filter = new WriteBufferLimitFilterBuilder();
+ * filter.attach( chain );
+ * </code></pre>
+ *
+ * @author The Apache Directory Project (mina-dev@directory.apache.org)
+ * @version $Rev: 619823 $, $Date: 2008-02-08 10:09:37 +0000 (Fri, 08 Feb 2008) $
+ */
+public class WriteBufferLimitFilterBuilder
+{
+ public static final String PENDING_SIZE = WriteBufferLimitFilterBuilder.class.getName() + ".pendingSize";
+
+ private static int DEFAULT_CONNECTION_BUFFER_MESSAGE_COUNT = 5000;
+
+ private volatile boolean throwNotBlock = false;
+
+ private volatile int maximumConnectionBufferCount;
+ private volatile long maximumConnectionBufferSize;
+
+ private final Object _blockLock = new Object();
+
+ private int _blockWaiters = 0;
+
+
+ public WriteBufferLimitFilterBuilder()
+ {
+ this(DEFAULT_CONNECTION_BUFFER_MESSAGE_COUNT);
+ }
+
+ public WriteBufferLimitFilterBuilder(int maxWriteBufferSize)
+ {
+ setMaximumConnectionBufferCount(maxWriteBufferSize);
+ }
+
+
+ /**
+ * Set the maximum amount pending items in the writeQueue for a given session.
+ * Changing the value will only take effect when new data is received for a
+ * connection, including existing connections. Default value is 5000 msgs.
+ *
+ * @param maximumConnectionBufferCount New buffer size. Must be > 0
+ */
+ public void setMaximumConnectionBufferCount(int maximumConnectionBufferCount)
+ {
+ this.maximumConnectionBufferCount = maximumConnectionBufferCount;
+ this.maximumConnectionBufferSize = 0;
+ }
+
+ public void setMaximumConnectionBufferSize(long maximumConnectionBufferSize)
+ {
+ this.maximumConnectionBufferSize = maximumConnectionBufferSize;
+ this.maximumConnectionBufferCount = 0;
+ }
+
+ /**
+ * Attach this filter to the specified filter chain. It will search for the ThreadPoolFilter, and attach itself
+ * before and after that filter.
+ *
+ * @param chain {@link IoFilterChain} to attach self to.
+ */
+ public void attach(IoFilterChain chain)
+ {
+ String name = getThreadPoolFilterEntryName(chain.getAll());
+
+ chain.addBefore(name, getClass().getName() + ".sendlimit", new SendLimit());
+ }
+
+ /**
+ * Attach this filter to the specified builder. It will search for the
+ * {@link ExecutorFilter}, and attach itself before and after that filter.
+ *
+ * @param builder {@link DefaultIoFilterChainBuilder} to attach self to.
+ */
+ public void attach(DefaultIoFilterChainBuilder builder)
+ {
+ String name = getThreadPoolFilterEntryName(builder.getAll());
+
+ builder.addBefore(name, getClass().getName() + ".sendlimit", new SendLimit());
+ }
+
+ private String getThreadPoolFilterEntryName(List entries)
+ {
+ Iterator i = entries.iterator();
+
+ while (i.hasNext())
+ {
+ IoFilterChain.Entry entry = (IoFilterChain.Entry) i.next();
+
+ if (entry.getFilter().getClass().isAssignableFrom(ExecutorFilter.class))
+ {
+ return entry.getName();
+ }
+ }
+
+ throw new IllegalStateException("Chain does not contain a ExecutorFilter");
+ }
+
+
+ public class SendLimit extends IoFilterAdapter
+ {
+ public void filterWrite(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) throws Exception
+ {
+ try
+ {
+ waitTillSendAllowed(session);
+ }
+ catch (WriteBufferFullExeception wbfe)
+ {
+ nextFilter.exceptionCaught(session, wbfe);
+ }
+
+ if (writeRequest.getMessage() instanceof ByteBuffer)
+ {
+ increasePendingWriteSize(session, (ByteBuffer) writeRequest.getMessage());
+ }
+
+ nextFilter.filterWrite(session, writeRequest);
+ }
+
+ private void increasePendingWriteSize(IoSession session, ByteBuffer message)
+ {
+ synchronized (session)
+ {
+ Long pendingSize = getScheduledWriteBytes(session) + message.remaining();
+ session.setAttribute(PENDING_SIZE, pendingSize);
+ }
+ }
+
+ private boolean sendAllowed(IoSession session)
+ {
+ if (session.isClosing())
+ {
+ return true;
+ }
+
+ int lmswm = maximumConnectionBufferCount;
+ long lmswb = maximumConnectionBufferSize;
+
+ return (lmswm == 0 || session.getScheduledWriteRequests() < lmswm)
+ && (lmswb == 0 || getScheduledWriteBytes(session) < lmswb);
+ }
+
+ private long getScheduledWriteBytes(IoSession session)
+ {
+ synchronized (session)
+ {
+ Long i = (Long) session.getAttribute(PENDING_SIZE);
+ return null == i ? 0 : i;
+ }
+ }
+
+ private void waitTillSendAllowed(IoSession session)
+ {
+ synchronized (_blockLock)
+ {
+ if (throwNotBlock)
+ {
+ throw new WriteBufferFullExeception();
+ }
+
+ _blockWaiters++;
+
+ while (!sendAllowed(session))
+ {
+ try
+ {
+ _blockLock.wait();
+ }
+ catch (InterruptedException e)
+ {
+ // Ignore.
+ }
+ }
+ _blockWaiters--;
+ }
+ }
+
+ public void messageSent(NextFilter nextFilter, IoSession session, Object message) throws Exception
+ {
+ if (message instanceof ByteBuffer)
+ {
+ decrementPendingWriteSize(session, (ByteBuffer) message);
+ }
+ notifyWaitingWriters();
+ nextFilter.messageSent(session, message);
+ }
+
+ private void decrementPendingWriteSize(IoSession session, ByteBuffer message)
+ {
+ synchronized (session)
+ {
+ session.setAttribute(PENDING_SIZE, getScheduledWriteBytes(session) - message.remaining());
+ }
+ }
+
+ private void notifyWaitingWriters()
+ {
+ synchronized (_blockLock)
+ {
+ if (_blockWaiters != 0)
+ {
+ _blockLock.notifyAll();
+ }
+ }
+
+ }
+
+ }//SentLimit
+
+
+}
diff --git a/java/common/src/main/java/org/apache/mina/filter/codec/OurCumulativeProtocolDecoder.java b/java/common/src/main/java/org/apache/mina/filter/codec/OurCumulativeProtocolDecoder.java
new file mode 100644
index 0000000000..3f7e206cb4
--- /dev/null
+++ b/java/common/src/main/java/org/apache/mina/filter/codec/OurCumulativeProtocolDecoder.java
@@ -0,0 +1,197 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.mina.filter.codec;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.IoSession;
+
+/**
+ * A {@link ProtocolDecoder} that cumulates the content of received
+ * buffers to a <em>cumulative buffer</em> to help users implement decoders.
+ * <p>
+ * If the received {@link ByteBuffer} is only a part of a message.
+ * decoders should cumulate received buffers to make a message complete or
+ * to postpone decoding until more buffers arrive.
+ * <p>
+ * Here is an example decoder that decodes CRLF terminated lines into
+ * <code>Command</code> objects:
+ * <pre>
+ * public class CRLFTerminatedCommandLineDecoder
+ * extends CumulativeProtocolDecoder {
+ *
+ * private Command parseCommand(ByteBuffer in) {
+ * // Convert the bytes in the specified buffer to a
+ * // Command object.
+ * ...
+ * }
+ *
+ * protected boolean doDecode(IoSession session, ByteBuffer in,
+ * ProtocolDecoderOutput out)
+ * throws Exception {
+ *
+ * // Remember the initial position.
+ * int start = in.position();
+ *
+ * // Now find the first CRLF in the buffer.
+ * byte previous = 0;
+ * while (in.hasRemaining()) {
+ * byte current = in.get();
+ *
+ * if (previous == '\r' && current == '\n') {
+ * // Remember the current position and limit.
+ * int position = in.position();
+ * int limit = in.limit();
+ * try {
+ * in.position(start);
+ * in.limit(position);
+ * // The bytes between in.position() and in.limit()
+ * // now contain a full CRLF terminated line.
+ * out.write(parseCommand(in.slice()));
+ * } finally {
+ * // Set the position to point right after the
+ * // detected line and set the limit to the old
+ * // one.
+ * in.position(position);
+ * in.limit(limit);
+ * }
+ * // Decoded one line; CumulativeProtocolDecoder will
+ * // call me again until I return false. So just
+ * // return true until there are no more lines in the
+ * // buffer.
+ * return true;
+ * }
+ *
+ * previous = current;
+ * }
+ *
+ * // Could not find CRLF in the buffer. Reset the initial
+ * // position to the one we recorded above.
+ * in.position(start);
+ *
+ * return false;
+ * }
+ * }
+ * </pre>
+ *
+ * @author The Apache Directory Project (mina-dev@directory.apache.org)
+ * @version $Rev: 619823 $, $Date: 2008-02-08 10:09:37 +0000 (Fri, 08 Feb 2008) $
+ */
+public abstract class OurCumulativeProtocolDecoder extends ProtocolDecoderAdapter {
+
+ private static final String BUFFER = OurCumulativeProtocolDecoder.class
+ .getName()
+ + ".Buffer";
+
+ /**
+ * Creates a new instance.
+ */
+ protected OurCumulativeProtocolDecoder() {
+ }
+
+ /**
+ * Cumulates content of <tt>in</tt> into internal buffer and forwards
+ * decoding request to {@link #doDecode(IoSession, ByteBuffer, ProtocolDecoderOutput)}.
+ * <tt>doDecode()</tt> is invoked repeatedly until it returns <tt>false</tt>
+ * and the cumulative buffer is NOT compacted after decoding ends.
+ *
+ * @throws IllegalStateException if your <tt>doDecode()</tt> returned
+ * <tt>true</tt> not consuming the cumulative buffer.
+ */
+ public void decode(IoSession session, ByteBuffer in,
+ ProtocolDecoderOutput out) throws Exception {
+ boolean usingSessionBuffer = true;
+ ByteBuffer buf = (ByteBuffer) session.getAttribute(BUFFER);
+ // If we have a session buffer, append data to that; otherwise
+ // use the buffer read from the network directly.
+ if (buf != null) {
+ buf.put(in);
+ buf.flip();
+ } else {
+ buf = in;
+ usingSessionBuffer = false;
+ }
+
+ for (;;) {
+ int oldPos = buf.position();
+ boolean decoded = doDecode(session, buf, out);
+ if (decoded) {
+ if (buf.position() == oldPos) {
+ throw new IllegalStateException(
+ "doDecode() can't return true when buffer is not consumed.");
+ }
+
+ if (!buf.hasRemaining()) {
+ break;
+ }
+ } else {
+ break;
+ }
+ }
+
+
+ // if there is any data left that cannot be decoded, we store
+ // it in a buffer in the session and next time this decoder is
+ // invoked the session buffer gets appended to
+ if (buf.hasRemaining()) {
+ storeRemainingInSession(buf, session);
+ } else {
+ if (usingSessionBuffer)
+ removeSessionBuffer(session);
+ }
+ }
+
+ /**
+ * Implement this method to consume the specified cumulative buffer and
+ * decode its content into message(s).
+ *
+ * @param in the cumulative buffer
+ * @return <tt>true</tt> if and only if there's more to decode in the buffer
+ * and you want to have <tt>doDecode</tt> method invoked again.
+ * Return <tt>false</tt> if remaining data is not enough to decode,
+ * then this method will be invoked again when more data is cumulated.
+ * @throws Exception if cannot decode <tt>in</tt>.
+ */
+ protected abstract boolean doDecode(IoSession session, ByteBuffer in,
+ ProtocolDecoderOutput out) throws Exception;
+
+ /**
+ * Releases the cumulative buffer used by the specified <tt>session</tt>.
+ * Please don't forget to call <tt>super.dispose( session )</tt> when
+ * you override this method.
+ */
+ public void dispose(IoSession session) throws Exception {
+ removeSessionBuffer(session);
+ }
+
+ private void removeSessionBuffer(IoSession session) {
+ ByteBuffer buf = (ByteBuffer) session.removeAttribute(BUFFER);
+ if (buf != null) {
+ buf.release();
+ }
+ }
+
+ private void storeRemainingInSession(ByteBuffer buf, IoSession session) {
+ ByteBuffer remainingBuf = ByteBuffer.allocate(buf.capacity());
+ remainingBuf.setAutoExpand(true);
+ remainingBuf.order(buf.order());
+ remainingBuf.put(buf);
+ session.setAttribute(BUFFER, remainingBuf);
+ }
+}
diff --git a/java/common/src/main/java/org/apache/mina/filter/codec/QpidProtocolCodecFilter.java b/java/common/src/main/java/org/apache/mina/filter/codec/QpidProtocolCodecFilter.java
new file mode 100644
index 0000000000..b8c6f29720
--- /dev/null
+++ b/java/common/src/main/java/org/apache/mina/filter/codec/QpidProtocolCodecFilter.java
@@ -0,0 +1,440 @@
+package org.apache.mina.filter.codec;
+
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+
+import org.apache.mina.common.*;
+import org.apache.mina.common.support.DefaultWriteFuture;
+import org.apache.mina.filter.codec.support.SimpleProtocolDecoderOutput;
+import org.apache.mina.util.SessionLog;
+import org.apache.mina.util.Queue;
+
+
+public class QpidProtocolCodecFilter extends IoFilterAdapter
+{
+ public static final String ENCODER = QpidProtocolCodecFilter.class.getName() + ".encoder";
+ public static final String DECODER = QpidProtocolCodecFilter.class.getName() + ".decoder";
+
+ private static final Class[] EMPTY_PARAMS = new Class[0];
+ private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.wrap( new byte[0] );
+
+ private final ProtocolCodecFactory factory;
+
+ public QpidProtocolCodecFilter( ProtocolCodecFactory factory )
+ {
+ if( factory == null )
+ {
+ throw new NullPointerException( "factory" );
+ }
+ this.factory = factory;
+ }
+
+ public QpidProtocolCodecFilter( final ProtocolEncoder encoder, final ProtocolDecoder decoder )
+ {
+ if( encoder == null )
+ {
+ throw new NullPointerException( "encoder" );
+ }
+ if( decoder == null )
+ {
+ throw new NullPointerException( "decoder" );
+ }
+
+ this.factory = new ProtocolCodecFactory()
+ {
+ public ProtocolEncoder getEncoder()
+ {
+ return encoder;
+ }
+
+ public ProtocolDecoder getDecoder()
+ {
+ return decoder;
+ }
+ };
+ }
+
+ public QpidProtocolCodecFilter( final Class encoderClass, final Class decoderClass )
+ {
+ if( encoderClass == null )
+ {
+ throw new NullPointerException( "encoderClass" );
+ }
+ if( decoderClass == null )
+ {
+ throw new NullPointerException( "decoderClass" );
+ }
+ if( !ProtocolEncoder.class.isAssignableFrom( encoderClass ) )
+ {
+ throw new IllegalArgumentException( "encoderClass: " + encoderClass.getName() );
+ }
+ if( !ProtocolDecoder.class.isAssignableFrom( decoderClass ) )
+ {
+ throw new IllegalArgumentException( "decoderClass: " + decoderClass.getName() );
+ }
+ try
+ {
+ encoderClass.getConstructor( EMPTY_PARAMS );
+ }
+ catch( NoSuchMethodException e )
+ {
+ throw new IllegalArgumentException( "encoderClass doesn't have a public default constructor." );
+ }
+ try
+ {
+ decoderClass.getConstructor( EMPTY_PARAMS );
+ }
+ catch( NoSuchMethodException e )
+ {
+ throw new IllegalArgumentException( "decoderClass doesn't have a public default constructor." );
+ }
+
+ this.factory = new ProtocolCodecFactory()
+ {
+ public ProtocolEncoder getEncoder() throws Exception
+ {
+ return ( ProtocolEncoder ) encoderClass.newInstance();
+ }
+
+ public ProtocolDecoder getDecoder() throws Exception
+ {
+ return ( ProtocolDecoder ) decoderClass.newInstance();
+ }
+ };
+ }
+
+ public void onPreAdd( IoFilterChain parent, String name, IoFilter.NextFilter nextFilter ) throws Exception
+ {
+ if( parent.contains( ProtocolCodecFilter.class ) )
+ {
+ throw new IllegalStateException( "A filter chain cannot contain more than one QpidProtocolCodecFilter." );
+ }
+ }
+
+ public void messageReceived( IoFilter.NextFilter nextFilter, IoSession session, Object message ) throws Exception
+ {
+ if( !( message instanceof ByteBuffer ) )
+ {
+ nextFilter.messageReceived( session, message );
+ return;
+ }
+
+ ByteBuffer in = ( ByteBuffer ) message;
+ ProtocolDecoder decoder = getDecoder( session );
+ ProtocolDecoderOutput decoderOut = getDecoderOut( session, nextFilter );
+
+ try
+ {
+ decoder.decode( session, in, decoderOut );
+ }
+ catch( Throwable t )
+ {
+ ProtocolDecoderException pde;
+ if( t instanceof ProtocolDecoderException )
+ {
+ pde = ( ProtocolDecoderException ) t;
+ }
+ else
+ {
+ pde = new ProtocolDecoderException( t );
+ }
+ pde.setHexdump( in.getHexDump() );
+ throw pde;
+ }
+ finally
+ {
+ // Dispose the decoder if this session is connectionless.
+ if( session.getTransportType().isConnectionless() )
+ {
+ disposeDecoder( session );
+ }
+
+ // Release the read buffer.
+ in.release();
+
+ decoderOut.flush();
+ }
+ }
+
+ public void messageSent( IoFilter.NextFilter nextFilter, IoSession session, Object message ) throws Exception
+ {
+ if( message instanceof HiddenByteBuffer )
+ {
+ return;
+ }
+
+ if( !( message instanceof MessageByteBuffer ) )
+ {
+ nextFilter.messageSent( session, message );
+ return;
+ }
+
+ nextFilter.messageSent( session, ( ( MessageByteBuffer ) message ).message );
+ }
+
+ public void filterWrite( IoFilter.NextFilter nextFilter, IoSession session, IoFilter.WriteRequest writeRequest ) throws Exception
+ {
+ Object message = writeRequest.getMessage();
+ if( message instanceof ByteBuffer )
+ {
+ nextFilter.filterWrite( session, writeRequest );
+ return;
+ }
+
+ ProtocolEncoder encoder = getEncoder( session );
+ ProtocolEncoderOutputImpl encoderOut = getEncoderOut( session, nextFilter, writeRequest );
+
+ try
+ {
+ encoder.encode( session, message, encoderOut );
+ encoderOut.flush();
+ nextFilter.filterWrite(
+ session,
+ new IoFilter.WriteRequest(
+ new MessageByteBuffer( writeRequest.getMessage() ),
+ writeRequest.getFuture(), writeRequest.getDestination() ) );
+ }
+ catch( Throwable t )
+ {
+ ProtocolEncoderException pee;
+ if( t instanceof ProtocolEncoderException )
+ {
+ pee = ( ProtocolEncoderException ) t;
+ }
+ else
+ {
+ pee = new ProtocolEncoderException( t );
+ }
+ throw pee;
+ }
+ finally
+ {
+ // Dispose the encoder if this session is connectionless.
+ if( session.getTransportType().isConnectionless() )
+ {
+ disposeEncoder( session );
+ }
+ }
+ }
+
+ public void sessionClosed( IoFilter.NextFilter nextFilter, IoSession session ) throws Exception
+ {
+ // Call finishDecode() first when a connection is closed.
+ ProtocolDecoder decoder = getDecoder( session );
+ ProtocolDecoderOutput decoderOut = getDecoderOut( session, nextFilter );
+ try
+ {
+ decoder.finishDecode( session, decoderOut );
+ }
+ catch( Throwable t )
+ {
+ ProtocolDecoderException pde;
+ if( t instanceof ProtocolDecoderException )
+ {
+ pde = ( ProtocolDecoderException ) t;
+ }
+ else
+ {
+ pde = new ProtocolDecoderException( t );
+ }
+ throw pde;
+ }
+ finally
+ {
+ // Dispose all.
+ disposeEncoder( session );
+ disposeDecoder( session );
+
+ decoderOut.flush();
+ }
+
+ nextFilter.sessionClosed( session );
+ }
+
+ private ProtocolEncoder getEncoder( IoSession session ) throws Exception
+ {
+ ProtocolEncoder encoder = ( ProtocolEncoder ) session.getAttribute( ENCODER );
+ if( encoder == null )
+ {
+ encoder = factory.getEncoder();
+ session.setAttribute( ENCODER, encoder );
+ }
+ return encoder;
+ }
+
+ private ProtocolEncoderOutputImpl getEncoderOut( IoSession session, IoFilter.NextFilter nextFilter, IoFilter.WriteRequest writeRequest )
+ {
+ return new ProtocolEncoderOutputImpl( session, nextFilter, writeRequest );
+ }
+
+ private ProtocolDecoder getDecoder( IoSession session ) throws Exception
+ {
+ ProtocolDecoder decoder = ( ProtocolDecoder ) session.getAttribute( DECODER );
+ if( decoder == null )
+ {
+ decoder = factory.getDecoder();
+ session.setAttribute( DECODER, decoder );
+ }
+ return decoder;
+ }
+
+ private ProtocolDecoderOutput getDecoderOut( IoSession session, IoFilter.NextFilter nextFilter )
+ {
+ return new SimpleProtocolDecoderOutput( session, nextFilter );
+ }
+
+ private void disposeEncoder( IoSession session )
+ {
+ ProtocolEncoder encoder = ( ProtocolEncoder ) session.removeAttribute( ENCODER );
+ if( encoder == null )
+ {
+ return;
+ }
+
+ try
+ {
+ encoder.dispose( session );
+ }
+ catch( Throwable t )
+ {
+ SessionLog.warn(
+ session,
+ "Failed to dispose: " + encoder.getClass().getName() +
+ " (" + encoder + ')' );
+ }
+ }
+
+ private void disposeDecoder( IoSession session )
+ {
+ ProtocolDecoder decoder = ( ProtocolDecoder ) session.removeAttribute( DECODER );
+ if( decoder == null )
+ {
+ return;
+ }
+
+ try
+ {
+ decoder.dispose( session );
+ }
+ catch( Throwable t )
+ {
+ SessionLog.warn(
+ session,
+ "Falied to dispose: " + decoder.getClass().getName() +
+ " (" + decoder + ')' );
+ }
+ }
+
+ private static class HiddenByteBuffer extends ByteBufferProxy
+ {
+ private HiddenByteBuffer( ByteBuffer buf )
+ {
+ super( buf );
+ }
+ }
+
+ private static class MessageByteBuffer extends ByteBufferProxy
+ {
+ private final Object message;
+
+ private MessageByteBuffer( Object message )
+ {
+ super( EMPTY_BUFFER );
+ this.message = message;
+ }
+
+ public void acquire()
+ {
+ // no-op since we are wraping a zero-byte buffer, this instance is to just curry the message
+ }
+
+ public void release()
+ {
+ // no-op since we are wraping a zero-byte buffer, this instance is to just curry the message
+ }
+ }
+
+ private static class ProtocolEncoderOutputImpl implements ProtocolEncoderOutput
+ {
+ private ByteBuffer buffer;
+
+ private final IoSession session;
+ private final IoFilter.NextFilter nextFilter;
+ private final IoFilter.WriteRequest writeRequest;
+
+ public ProtocolEncoderOutputImpl( IoSession session, IoFilter.NextFilter nextFilter, IoFilter.WriteRequest writeRequest )
+ {
+ this.session = session;
+ this.nextFilter = nextFilter;
+ this.writeRequest = writeRequest;
+ }
+
+
+
+ public void write( ByteBuffer buf )
+ {
+ if(buffer != null)
+ {
+ flush();
+ }
+ buffer = buf;
+ }
+
+ public void mergeAll()
+ {
+ }
+
+ public WriteFuture flush()
+ {
+ WriteFuture future = null;
+ if( buffer == null )
+ {
+ return null;
+ }
+ else
+ {
+ ByteBuffer buf = buffer;
+ // Flush only when the buffer has remaining.
+ if( buf.hasRemaining() )
+ {
+ future = doFlush( buf );
+ }
+
+ }
+
+ return future;
+ }
+
+
+ protected WriteFuture doFlush( ByteBuffer buf )
+ {
+ WriteFuture future = new DefaultWriteFuture( session );
+ nextFilter.filterWrite(
+ session,
+ new IoFilter.WriteRequest(
+ buf,
+ future, writeRequest.getDestination() ) );
+ return future;
+ }
+ }
+}
+
diff --git a/java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketAcceptor.java b/java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketAcceptor.java
new file mode 100644
index 0000000000..e5360d32e0
--- /dev/null
+++ b/java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketAcceptor.java
@@ -0,0 +1,547 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.mina.transport.socket.nio;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.ServerSocketChannel;
+import java.nio.channels.SocketChannel;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.mina.common.ExceptionMonitor;
+import org.apache.mina.common.IoAcceptor;
+import org.apache.mina.common.IoHandler;
+import org.apache.mina.common.IoServiceConfig;
+import org.apache.mina.common.support.BaseIoAcceptor;
+import org.apache.mina.util.Queue;
+import org.apache.mina.util.NewThreadExecutor;
+import org.apache.mina.util.NamePreservingRunnable;
+import edu.emory.mathcs.backport.java.util.concurrent.Executor;
+
+/**
+ * {@link IoAcceptor} for socket transport (TCP/IP).
+ *
+ * @author The Apache Directory Project (mina-dev@directory.apache.org)
+ * @version $Rev: 619823 $, $Date: 2008-02-08 10:09:37 +0000 (Fri, 08 Feb 2008) $
+ */
+public class MultiThreadSocketAcceptor extends SocketAcceptor
+{
+ /**
+ * @noinspection StaticNonFinalField
+ */
+ private static volatile int nextId = 0;
+
+ private final Executor executor;
+ private final Object lock = new Object();
+ private final int id = nextId ++;
+ private final String threadName = "SocketAcceptor-" + id;
+ private final Map channels = new HashMap();
+
+ private final Queue registerQueue = new Queue();
+ private final Queue cancelQueue = new Queue();
+
+ private final MultiThreadSocketIoProcessor[] ioProcessors;
+ private final int processorCount;
+
+ /**
+ * @noinspection FieldAccessedSynchronizedAndUnsynchronized
+ */
+ private Selector selector;
+ private Worker worker;
+ private int processorDistributor = 0;
+
+ /**
+ * Create an acceptor with a single processing thread using a NewThreadExecutor
+ */
+ public MultiThreadSocketAcceptor()
+ {
+ this( 1, new NewThreadExecutor() );
+ }
+
+ /**
+ * Create an acceptor with the desired number of processing threads
+ *
+ * @param processorCount Number of processing threads
+ * @param executor Executor to use for launching threads
+ */
+ public MultiThreadSocketAcceptor( int processorCount, Executor executor )
+ {
+ if( processorCount < 1 )
+ {
+ throw new IllegalArgumentException( "Must have at least one processor" );
+ }
+
+ this.executor = executor;
+ this.processorCount = processorCount;
+ ioProcessors = new MultiThreadSocketIoProcessor[processorCount];
+
+ for( int i = 0; i < processorCount; i++ )
+ {
+ ioProcessors[i] = new MultiThreadSocketIoProcessor( "SocketAcceptorIoProcessor-" + id + "." + i, executor );
+ }
+ }
+
+
+ /**
+ * Binds to the specified <code>address</code> and handles incoming connections with the specified
+ * <code>handler</code>. Backlog value is configured to the value of <code>backlog</code> property.
+ *
+ * @throws IOException if failed to bind
+ */
+ public void bind( SocketAddress address, IoHandler handler, IoServiceConfig config ) throws IOException
+ {
+ if( handler == null )
+ {
+ throw new NullPointerException( "handler" );
+ }
+
+ if( address != null && !( address instanceof InetSocketAddress ) )
+ {
+ throw new IllegalArgumentException( "Unexpected address type: " + address.getClass() );
+ }
+
+ if( config == null )
+ {
+ config = getDefaultConfig();
+ }
+
+ RegistrationRequest request = new RegistrationRequest( address, handler, config );
+
+ synchronized( registerQueue )
+ {
+ registerQueue.push( request );
+ }
+
+ startupWorker();
+
+ selector.wakeup();
+
+ synchronized( request )
+ {
+ while( !request.done )
+ {
+ try
+ {
+ request.wait();
+ }
+ catch( InterruptedException e )
+ {
+ ExceptionMonitor.getInstance().exceptionCaught( e );
+ }
+ }
+ }
+
+ if( request.exception != null )
+ {
+ throw request.exception;
+ }
+ }
+
+
+ private synchronized void startupWorker() throws IOException
+ {
+ synchronized( lock )
+ {
+ if( worker == null )
+ {
+ selector = Selector.open();
+ worker = new Worker();
+
+ executor.execute( new NamePreservingRunnable( worker ) );
+ }
+ }
+ }
+
+ public void unbind( SocketAddress address )
+ {
+ if( address == null )
+ {
+ throw new NullPointerException( "address" );
+ }
+
+ CancellationRequest request = new CancellationRequest( address );
+
+ try
+ {
+ startupWorker();
+ }
+ catch( IOException e )
+ {
+ // IOException is thrown only when Worker thread is not
+ // running and failed to open a selector. We simply throw
+ // IllegalArgumentException here because we can simply
+ // conclude that nothing is bound to the selector.
+ throw new IllegalArgumentException( "Address not bound: " + address );
+ }
+
+ synchronized( cancelQueue )
+ {
+ cancelQueue.push( request );
+ }
+
+ selector.wakeup();
+
+ synchronized( request )
+ {
+ while( !request.done )
+ {
+ try
+ {
+ request.wait();
+ }
+ catch( InterruptedException e )
+ {
+ ExceptionMonitor.getInstance().exceptionCaught( e );
+ }
+ }
+ }
+
+ if( request.exception != null )
+ {
+ request.exception.fillInStackTrace();
+
+ throw request.exception;
+ }
+ }
+
+
+ private class Worker implements Runnable
+ {
+ public void run()
+ {
+ Thread.currentThread().setName(MultiThreadSocketAcceptor.this.threadName );
+
+ for( ; ; )
+ {
+ try
+ {
+ int nKeys = selector.select();
+
+ registerNew();
+
+ if( nKeys > 0 )
+ {
+ processSessions( selector.selectedKeys() );
+ }
+
+ cancelKeys();
+
+ if( selector.keys().isEmpty() )
+ {
+ synchronized( lock )
+ {
+ if( selector.keys().isEmpty() &&
+ registerQueue.isEmpty() &&
+ cancelQueue.isEmpty() )
+ {
+ worker = null;
+ try
+ {
+ selector.close();
+ }
+ catch( IOException e )
+ {
+ ExceptionMonitor.getInstance().exceptionCaught( e );
+ }
+ finally
+ {
+ selector = null;
+ }
+ break;
+ }
+ }
+ }
+ }
+ catch( IOException e )
+ {
+ ExceptionMonitor.getInstance().exceptionCaught( e );
+
+ try
+ {
+ Thread.sleep( 1000 );
+ }
+ catch( InterruptedException e1 )
+ {
+ ExceptionMonitor.getInstance().exceptionCaught( e1 );
+ }
+ }
+ }
+ }
+
+ private void processSessions( Set keys ) throws IOException
+ {
+ Iterator it = keys.iterator();
+ while( it.hasNext() )
+ {
+ SelectionKey key = ( SelectionKey ) it.next();
+
+ it.remove();
+
+ if( !key.isAcceptable() )
+ {
+ continue;
+ }
+
+ ServerSocketChannel ssc = ( ServerSocketChannel ) key.channel();
+
+ SocketChannel ch = ssc.accept();
+
+ if( ch == null )
+ {
+ continue;
+ }
+
+ boolean success = false;
+ try
+ {
+
+ RegistrationRequest req = ( RegistrationRequest ) key.attachment();
+
+ MultiThreadSocketSessionImpl session = new MultiThreadSocketSessionImpl(
+ MultiThreadSocketAcceptor.this, nextProcessor(), getListeners(),
+ req.config, ch, req.handler, req.address );
+
+ // New Interface
+// SocketSessionImpl session = new SocketSessionImpl(
+// SocketAcceptor.this, nextProcessor(), getListeners(),
+// req.config, ch, req.handler, req.address );
+
+
+ getFilterChainBuilder().buildFilterChain( session.getFilterChain() );
+ req.config.getFilterChainBuilder().buildFilterChain( session.getFilterChain() );
+ req.config.getThreadModel().buildFilterChain( session.getFilterChain() );
+ session.getIoProcessor().addNew( session );
+ success = true;
+ }
+ catch( Throwable t )
+ {
+ ExceptionMonitor.getInstance().exceptionCaught( t );
+ }
+ finally
+ {
+ if( !success )
+ {
+ ch.close();
+ }
+ }
+ }
+ }
+ }
+
+ private MultiThreadSocketIoProcessor nextProcessor()
+ {
+ return ioProcessors[processorDistributor++ % processorCount];
+ }
+
+
+ private void registerNew()
+ {
+ if( registerQueue.isEmpty() )
+ {
+ return;
+ }
+
+ for( ; ; )
+ {
+ RegistrationRequest req;
+
+ synchronized( registerQueue )
+ {
+ req = ( RegistrationRequest ) registerQueue.pop();
+ }
+
+ if( req == null )
+ {
+ break;
+ }
+
+ ServerSocketChannel ssc = null;
+
+ try
+ {
+ ssc = ServerSocketChannel.open();
+ ssc.configureBlocking( false );
+
+ // Configure the server socket,
+ SocketAcceptorConfig cfg;
+ if( req.config instanceof SocketAcceptorConfig )
+ {
+ cfg = ( SocketAcceptorConfig ) req.config;
+ }
+ else
+ {
+ cfg = ( SocketAcceptorConfig ) getDefaultConfig();
+ }
+
+ ssc.socket().setReuseAddress( cfg.isReuseAddress() );
+ ssc.socket().setReceiveBufferSize(
+ ( ( SocketSessionConfig ) cfg.getSessionConfig() ).getReceiveBufferSize() );
+
+ // and bind.
+ ssc.socket().bind( req.address, cfg.getBacklog() );
+ if( req.address == null || req.address.getPort() == 0 )
+ {
+ req.address = ( InetSocketAddress ) ssc.socket().getLocalSocketAddress();
+ }
+ ssc.register( selector, SelectionKey.OP_ACCEPT, req );
+
+ synchronized( channels )
+ {
+ channels.put( req.address, ssc );
+ }
+
+ getListeners().fireServiceActivated(
+ this, req.address, req.handler, req.config );
+ }
+ catch( IOException e )
+ {
+ req.exception = e;
+ }
+ finally
+ {
+ synchronized( req )
+ {
+ req.done = true;
+
+ req.notifyAll();
+ }
+
+ if( ssc != null && req.exception != null )
+ {
+ try
+ {
+ ssc.close();
+ }
+ catch( IOException e )
+ {
+ ExceptionMonitor.getInstance().exceptionCaught( e );
+ }
+ }
+ }
+ }
+ }
+
+
+ private void cancelKeys()
+ {
+ if( cancelQueue.isEmpty() )
+ {
+ return;
+ }
+
+ for( ; ; )
+ {
+ CancellationRequest request;
+
+ synchronized( cancelQueue )
+ {
+ request = ( CancellationRequest ) cancelQueue.pop();
+ }
+
+ if( request == null )
+ {
+ break;
+ }
+
+ ServerSocketChannel ssc;
+ synchronized( channels )
+ {
+ ssc = ( ServerSocketChannel ) channels.remove( request.address );
+ }
+
+ // close the channel
+ try
+ {
+ if( ssc == null )
+ {
+ request.exception = new IllegalArgumentException( "Address not bound: " + request.address );
+ }
+ else
+ {
+ SelectionKey key = ssc.keyFor( selector );
+ request.registrationRequest = ( RegistrationRequest ) key.attachment();
+ key.cancel();
+
+ selector.wakeup(); // wake up again to trigger thread death
+
+ ssc.close();
+ }
+ }
+ catch( IOException e )
+ {
+ ExceptionMonitor.getInstance().exceptionCaught( e );
+ }
+ finally
+ {
+ synchronized( request )
+ {
+ request.done = true;
+ request.notifyAll();
+ }
+
+ if( request.exception == null )
+ {
+ getListeners().fireServiceDeactivated(
+ this, request.address,
+ request.registrationRequest.handler,
+ request.registrationRequest.config );
+ }
+ }
+ }
+ }
+
+ private static class RegistrationRequest
+ {
+ private InetSocketAddress address;
+ private final IoHandler handler;
+ private final IoServiceConfig config;
+ private IOException exception;
+ private boolean done;
+
+ private RegistrationRequest( SocketAddress address, IoHandler handler, IoServiceConfig config )
+ {
+ this.address = ( InetSocketAddress ) address;
+ this.handler = handler;
+ this.config = config;
+ }
+ }
+
+
+ private static class CancellationRequest
+ {
+ private final SocketAddress address;
+ private boolean done;
+ private RegistrationRequest registrationRequest;
+ private RuntimeException exception;
+
+ private CancellationRequest( SocketAddress address )
+ {
+ this.address = address;
+ }
+ }
+}
diff --git a/java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketConnector.java b/java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketConnector.java
new file mode 100644
index 0000000000..7344f70078
--- /dev/null
+++ b/java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketConnector.java
@@ -0,0 +1,486 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.mina.transport.socket.nio;
+
+import edu.emory.mathcs.backport.java.util.concurrent.Executor;
+import org.apache.mina.common.ConnectFuture;
+import org.apache.mina.common.ExceptionMonitor;
+import org.apache.mina.common.IoConnector;
+import org.apache.mina.common.IoConnectorConfig;
+import org.apache.mina.common.IoHandler;
+import org.apache.mina.common.IoServiceConfig;
+import org.apache.mina.common.support.AbstractIoFilterChain;
+import org.apache.mina.common.support.DefaultConnectFuture;
+import org.apache.mina.util.NamePreservingRunnable;
+import org.apache.mina.util.NewThreadExecutor;
+import org.apache.mina.util.Queue;
+
+import java.io.IOException;
+import java.net.ConnectException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * {@link IoConnector} for socket transport (TCP/IP).
+ *
+ * @author The Apache Directory Project (mina-dev@directory.apache.org)
+ * @version $Rev: 619823 $, $Date: 2008-02-08 10:09:37 +0000 (Fri, 08 Feb 2008) $
+ */
+public class MultiThreadSocketConnector extends SocketConnector
+{
+ /** @noinspection StaticNonFinalField */
+ private static volatile int nextId = 0;
+
+ private final Object lock = new Object();
+ private final int id = nextId++;
+ private final String threadName = "SocketConnector-" + id;
+
+ private final Queue connectQueue = new Queue();
+ private final MultiThreadSocketIoProcessor[] ioProcessors;
+ private final int processorCount;
+ private final Executor executor;
+
+ /** @noinspection FieldAccessedSynchronizedAndUnsynchronized */
+ private Selector selector;
+ private Worker worker;
+ private int processorDistributor = 0;
+ private int workerTimeout = 60; // 1 min.
+
+ /** Create a connector with a single processing thread using a NewThreadExecutor */
+ public MultiThreadSocketConnector()
+ {
+ this(1, new NewThreadExecutor());
+ }
+
+ /**
+ * Create a connector with the desired number of processing threads
+ *
+ * @param processorCount Number of processing threads
+ * @param executor Executor to use for launching threads
+ */
+ public MultiThreadSocketConnector(int processorCount, Executor executor)
+ {
+ if (processorCount < 1)
+ {
+ throw new IllegalArgumentException("Must have at least one processor");
+ }
+
+ this.executor = executor;
+ this.processorCount = processorCount;
+ ioProcessors = new MultiThreadSocketIoProcessor[processorCount];
+
+ for (int i = 0; i < processorCount; i++)
+ {
+ ioProcessors[i] = new MultiThreadSocketIoProcessor("SocketConnectorIoProcessor-" + id + "." + i, executor);
+ }
+ }
+
+ /**
+ * How many seconds to keep the connection thread alive between connection requests
+ *
+ * @return Number of seconds to keep connection thread alive
+ */
+ public int getWorkerTimeout()
+ {
+ return workerTimeout;
+ }
+
+ /**
+ * Set how many seconds the connection worker thread should remain alive once idle before terminating itself.
+ *
+ * @param workerTimeout Number of seconds to keep thread alive. Must be >=0
+ */
+ public void setWorkerTimeout(int workerTimeout)
+ {
+ if (workerTimeout < 0)
+ {
+ throw new IllegalArgumentException("Must be >= 0");
+ }
+ this.workerTimeout = workerTimeout;
+ }
+
+ public ConnectFuture connect(SocketAddress address, IoHandler handler, IoServiceConfig config)
+ {
+ return connect(address, null, handler, config);
+ }
+
+ public ConnectFuture connect(SocketAddress address, SocketAddress localAddress,
+ IoHandler handler, IoServiceConfig config)
+ {
+ if (address == null)
+ {
+ throw new NullPointerException("address");
+ }
+ if (handler == null)
+ {
+ throw new NullPointerException("handler");
+ }
+
+ if (!(address instanceof InetSocketAddress))
+ {
+ throw new IllegalArgumentException("Unexpected address type: "
+ + address.getClass());
+ }
+
+ if (localAddress != null && !(localAddress instanceof InetSocketAddress))
+ {
+ throw new IllegalArgumentException("Unexpected local address type: "
+ + localAddress.getClass());
+ }
+
+ if (config == null)
+ {
+ config = getDefaultConfig();
+ }
+
+ SocketChannel ch = null;
+ boolean success = false;
+ try
+ {
+ ch = SocketChannel.open();
+ ch.socket().setReuseAddress(true);
+ if (localAddress != null)
+ {
+ ch.socket().bind(localAddress);
+ }
+
+ ch.configureBlocking(false);
+
+ if (ch.connect(address))
+ {
+ DefaultConnectFuture future = new DefaultConnectFuture();
+ newSession(ch, handler, config, future);
+ success = true;
+ return future;
+ }
+
+ success = true;
+ }
+ catch (IOException e)
+ {
+ return DefaultConnectFuture.newFailedFuture(e);
+ }
+ finally
+ {
+ if (!success && ch != null)
+ {
+ try
+ {
+ ch.close();
+ }
+ catch (IOException e)
+ {
+ ExceptionMonitor.getInstance().exceptionCaught(e);
+ }
+ }
+ }
+
+ ConnectionRequest request = new ConnectionRequest(ch, handler, config);
+ synchronized (lock)
+ {
+ try
+ {
+ startupWorker();
+ }
+ catch (IOException e)
+ {
+ try
+ {
+ ch.close();
+ }
+ catch (IOException e2)
+ {
+ ExceptionMonitor.getInstance().exceptionCaught(e2);
+ }
+
+ return DefaultConnectFuture.newFailedFuture(e);
+ }
+ }
+
+ synchronized (connectQueue)
+ {
+ connectQueue.push(request);
+ }
+ selector.wakeup();
+
+ return request;
+ }
+
+ private synchronized void startupWorker() throws IOException
+ {
+ if (worker == null)
+ {
+ selector = Selector.open();
+ worker = new Worker();
+ executor.execute(new NamePreservingRunnable(worker));
+ }
+ }
+
+ private void registerNew()
+ {
+ if (connectQueue.isEmpty())
+ {
+ return;
+ }
+
+ for (; ;)
+ {
+ ConnectionRequest req;
+ synchronized (connectQueue)
+ {
+ req = (ConnectionRequest) connectQueue.pop();
+ }
+
+ if (req == null)
+ {
+ break;
+ }
+
+ SocketChannel ch = req.channel;
+ try
+ {
+ ch.register(selector, SelectionKey.OP_CONNECT, req);
+ }
+ catch (IOException e)
+ {
+ req.setException(e);
+ }
+ }
+ }
+
+ private void processSessions(Set keys)
+ {
+ Iterator it = keys.iterator();
+
+ while (it.hasNext())
+ {
+ SelectionKey key = (SelectionKey) it.next();
+
+ if (!key.isConnectable())
+ {
+ continue;
+ }
+
+ SocketChannel ch = (SocketChannel) key.channel();
+ ConnectionRequest entry = (ConnectionRequest) key.attachment();
+
+ boolean success = false;
+ try
+ {
+ ch.finishConnect();
+ newSession(ch, entry.handler, entry.config, entry);
+ success = true;
+ }
+ catch (Throwable e)
+ {
+ entry.setException(e);
+ }
+ finally
+ {
+ key.cancel();
+ if (!success)
+ {
+ try
+ {
+ ch.close();
+ }
+ catch (IOException e)
+ {
+ ExceptionMonitor.getInstance().exceptionCaught(e);
+ }
+ }
+ }
+ }
+
+ keys.clear();
+ }
+
+ private void processTimedOutSessions(Set keys)
+ {
+ long currentTime = System.currentTimeMillis();
+ Iterator it = keys.iterator();
+
+ while (it.hasNext())
+ {
+ SelectionKey key = (SelectionKey) it.next();
+
+ if (!key.isValid())
+ {
+ continue;
+ }
+
+ ConnectionRequest entry = (ConnectionRequest) key.attachment();
+
+ if (currentTime >= entry.deadline)
+ {
+ entry.setException(new ConnectException());
+ try
+ {
+ key.channel().close();
+ }
+ catch (IOException e)
+ {
+ ExceptionMonitor.getInstance().exceptionCaught(e);
+ }
+ finally
+ {
+ key.cancel();
+ }
+ }
+ }
+ }
+
+ private void newSession(SocketChannel ch, IoHandler handler, IoServiceConfig config, ConnectFuture connectFuture)
+ throws IOException
+ {
+ MultiThreadSocketSessionImpl session =
+ new MultiThreadSocketSessionImpl(this, nextProcessor(), getListeners(),
+ config, ch, handler, ch.socket().getRemoteSocketAddress());
+
+ //new interface
+// SocketSessionImpl session = new SocketSessionImpl(
+// this, nextProcessor(), getListeners(),
+// config, ch, handler, ch.socket().getRemoteSocketAddress() );
+ try
+ {
+ getFilterChainBuilder().buildFilterChain(session.getFilterChain());
+ config.getFilterChainBuilder().buildFilterChain(session.getFilterChain());
+ config.getThreadModel().buildFilterChain(session.getFilterChain());
+ }
+ catch (Throwable e)
+ {
+ throw (IOException) new IOException("Failed to create a session.").initCause(e);
+ }
+
+ // Set the ConnectFuture of the specified session, which will be
+ // removed and notified by AbstractIoFilterChain eventually.
+ session.setAttribute( AbstractIoFilterChain.CONNECT_FUTURE, connectFuture );
+
+ // Forward the remaining process to the SocketIoProcessor.
+ session.getIoProcessor().addNew(session);
+ }
+
+ private MultiThreadSocketIoProcessor nextProcessor()
+ {
+ return ioProcessors[processorDistributor++ % processorCount];
+ }
+
+ private class Worker implements Runnable
+ {
+ private long lastActive = System.currentTimeMillis();
+
+ public void run()
+ {
+ Thread.currentThread().setName(MultiThreadSocketConnector.this.threadName);
+
+ for (; ;)
+ {
+ try
+ {
+ int nKeys = selector.select(1000);
+
+ registerNew();
+
+ if (nKeys > 0)
+ {
+ processSessions(selector.selectedKeys());
+ }
+
+ processTimedOutSessions(selector.keys());
+
+ if (selector.keys().isEmpty())
+ {
+ if (System.currentTimeMillis() - lastActive > workerTimeout * 1000L)
+ {
+ synchronized (lock)
+ {
+ if (selector.keys().isEmpty() &&
+ connectQueue.isEmpty())
+ {
+ worker = null;
+ try
+ {
+ selector.close();
+ }
+ catch (IOException e)
+ {
+ ExceptionMonitor.getInstance().exceptionCaught(e);
+ }
+ finally
+ {
+ selector = null;
+ }
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ lastActive = System.currentTimeMillis();
+ }
+ }
+ catch (IOException e)
+ {
+ ExceptionMonitor.getInstance().exceptionCaught(e);
+
+ try
+ {
+ Thread.sleep(1000);
+ }
+ catch (InterruptedException e1)
+ {
+ ExceptionMonitor.getInstance().exceptionCaught(e1);
+ }
+ }
+ }
+ }
+ }
+
+ private class ConnectionRequest extends DefaultConnectFuture
+ {
+ private final SocketChannel channel;
+ private final long deadline;
+ private final IoHandler handler;
+ private final IoServiceConfig config;
+
+ private ConnectionRequest(SocketChannel channel, IoHandler handler, IoServiceConfig config)
+ {
+ this.channel = channel;
+ long timeout;
+ if (config instanceof IoConnectorConfig)
+ {
+ timeout = ((IoConnectorConfig) config).getConnectTimeoutMillis();
+ }
+ else
+ {
+ timeout = ((IoConnectorConfig) getDefaultConfig()).getConnectTimeoutMillis();
+ }
+ this.deadline = System.currentTimeMillis() + timeout;
+ this.handler = handler;
+ this.config = config;
+ }
+ }
+}
diff --git a/java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketFilterChain.java b/java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketFilterChain.java
new file mode 100644
index 0000000000..67b8c8d820
--- /dev/null
+++ b/java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketFilterChain.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.mina.transport.socket.nio;
+
+import java.io.IOException;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.IoFilterChain;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.common.IoFilter.WriteRequest;
+import org.apache.mina.common.support.AbstractIoFilterChain;
+import org.apache.mina.util.Queue;
+
+/**
+ * An {@link IoFilterChain} for socket transport (TCP/IP).
+ *
+ * @author The Apache Directory Project (mina-dev@directory.apache.org)
+ */
+class MultiThreadSocketFilterChain extends AbstractIoFilterChain {
+
+ MultiThreadSocketFilterChain( IoSession parent )
+ {
+ super( parent );
+ }
+
+ protected void doWrite( IoSession session, WriteRequest writeRequest )
+ {
+ MultiThreadSocketSessionImpl s = (MultiThreadSocketSessionImpl) session;
+ Queue writeRequestQueue = s.getWriteRequestQueue();
+
+ // SocketIoProcessor.doFlush() will reset it after write is finished
+ // because the buffer will be passed with messageSent event.
+ ( ( ByteBuffer ) writeRequest.getMessage() ).mark();
+ synchronized( writeRequestQueue )
+ {
+ writeRequestQueue.push( writeRequest );
+ if( writeRequestQueue.size() == 1 && session.getTrafficMask().isWritable() )
+ {
+ // Notify SocketIoProcessor only when writeRequestQueue was empty.
+ s.getIoProcessor().flush( s );
+ }
+ }
+ }
+
+ protected void doClose( IoSession session ) throws IOException
+ {
+ MultiThreadSocketSessionImpl s = (MultiThreadSocketSessionImpl) session;
+ s.getIoProcessor().remove( s );
+ }
+}
diff --git a/java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketIoProcessor.java b/java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketIoProcessor.java
new file mode 100644
index 0000000000..c23ad8686f
--- /dev/null
+++ b/java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketIoProcessor.java
@@ -0,0 +1,1026 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.mina.transport.socket.nio;
+
+import edu.emory.mathcs.backport.java.util.concurrent.Executor;
+import edu.emory.mathcs.backport.java.util.concurrent.locks.ReentrantLock;
+import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.ExceptionMonitor;
+import org.apache.mina.common.IdleStatus;
+import org.apache.mina.common.IoFilter.WriteRequest;
+import org.apache.mina.common.WriteTimeoutException;
+import org.apache.mina.util.IdentityHashSet;
+import org.apache.mina.util.NamePreservingRunnable;
+import org.apache.mina.util.Queue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.SocketChannel;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * Performs all I/O operations for sockets which is connected or bound. This class is used by MINA internally.
+ *
+ * @author The Apache Directory Project (mina-dev@directory.apache.org)
+ * @version $Rev: 619823 $, $Date: 2008-02-08 10:09:37 +0000 (Fri, 08 Feb 2008) $,
+ */
+class MultiThreadSocketIoProcessor extends SocketIoProcessor
+{
+ Logger _logger = LoggerFactory.getLogger(MultiThreadSocketIoProcessor.class);
+ Logger _loggerRead = LoggerFactory.getLogger(MultiThreadSocketIoProcessor.class + ".Reader");
+ Logger _loggerWrite = LoggerFactory.getLogger(MultiThreadSocketIoProcessor.class + ".Writer");
+
+ private static final long SELECTOR_TIMEOUT = 1000L;
+
+ private int MAX_READ_BYTES_PER_SESSION = 524288; //512K
+ private int MAX_FLUSH_BYTES_PER_SESSION = 524288; //512K
+
+ private final Object readLock = new Object();
+ private final Object writeLock = new Object();
+
+ private final String threadName;
+ private final Executor executor;
+
+ private ReentrantLock trafficMaskUpdateLock = new ReentrantLock();
+
+ /** @noinspection FieldAccessedSynchronizedAndUnsynchronized */
+ private volatile Selector selector, writeSelector;
+
+ private final Queue newSessions = new Queue();
+ private final Queue removingSessions = new Queue();
+ private final BlockingQueue flushingSessions = new LinkedBlockingQueue();
+ private final IdentityHashSet flushingSessionsSet = new IdentityHashSet();
+
+ private final Queue trafficControllingSessions = new Queue();
+
+ private ReadWorker readWorker;
+ private WriteWorker writeWorker;
+ private long lastIdleReadCheckTime = System.currentTimeMillis();
+ private long lastIdleWriteCheckTime = System.currentTimeMillis();
+
+ MultiThreadSocketIoProcessor(String threadName, Executor executor)
+ {
+ super(threadName, executor);
+ this.threadName = threadName;
+ this.executor = executor;
+ }
+
+ void addNew(SocketSessionImpl session) throws IOException
+ {
+ synchronized (newSessions)
+ {
+ newSessions.push(session);
+ }
+
+ startupWorker();
+
+ selector.wakeup();
+ writeSelector.wakeup();
+ }
+
+ void remove(SocketSessionImpl session) throws IOException
+ {
+ scheduleRemove(session);
+ startupWorker();
+ selector.wakeup();
+ }
+
+ private void startupWorker() throws IOException
+ {
+ synchronized (readLock)
+ {
+ if (readWorker == null)
+ {
+ selector = Selector.open();
+ readWorker = new ReadWorker();
+ executor.execute(new NamePreservingRunnable(readWorker));
+ }
+ }
+
+ synchronized (writeLock)
+ {
+ if (writeWorker == null)
+ {
+ writeSelector = Selector.open();
+ writeWorker = new WriteWorker();
+ executor.execute(new NamePreservingRunnable(writeWorker));
+ }
+ }
+
+ }
+
+ void flush(SocketSessionImpl session)
+ {
+ scheduleFlush(session);
+ Selector selector = this.writeSelector;
+
+ if (selector != null)
+ {
+ selector.wakeup();
+ }
+ }
+
+ void updateTrafficMask(SocketSessionImpl session)
+ {
+ scheduleTrafficControl(session);
+ Selector selector = this.selector;
+ if (selector != null)
+ {
+ selector.wakeup();
+ }
+ }
+
+ private void scheduleRemove(SocketSessionImpl session)
+ {
+ synchronized (removingSessions)
+ {
+ removingSessions.push(session);
+ }
+ }
+
+ private void scheduleFlush(SocketSessionImpl session)
+ {
+ synchronized (flushingSessionsSet)
+ {
+ //if flushingSessions grows to contain Integer.MAX_VALUE sessions
+ // then this will fail.
+ if (flushingSessionsSet.add(session))
+ {
+ flushingSessions.offer(session);
+ }
+ }
+ }
+
+ private void scheduleTrafficControl(SocketSessionImpl session)
+ {
+ synchronized (trafficControllingSessions)
+ {
+ trafficControllingSessions.push(session);
+ }
+ }
+
+ private void doAddNewReader() throws InterruptedException
+ {
+ if (newSessions.isEmpty())
+ {
+ return;
+ }
+
+ for (; ;)
+ {
+ MultiThreadSocketSessionImpl session;
+
+ synchronized (newSessions)
+ {
+ session = (MultiThreadSocketSessionImpl) newSessions.peek();
+ }
+
+ if (session == null)
+ {
+ break;
+ }
+
+ SocketChannel ch = session.getChannel();
+
+
+ try
+ {
+
+ ch.configureBlocking(false);
+ session.setSelectionKey(ch.register(selector,
+ SelectionKey.OP_READ,
+ session));
+
+ //System.out.println("ReadDebug:"+"Awaiting Registration");
+ session.awaitRegistration();
+ sessionCreated(session);
+ }
+ catch (IOException e)
+ {
+ // Clear the AbstractIoFilterChain.CONNECT_FUTURE attribute
+ // and call ConnectFuture.setException().
+ session.getFilterChain().fireExceptionCaught(session, e);
+ }
+ }
+ }
+
+
+ private void doAddNewWrite() throws InterruptedException
+ {
+ if (newSessions.isEmpty())
+ {
+ return;
+ }
+
+ for (; ;)
+ {
+ MultiThreadSocketSessionImpl session;
+
+ synchronized (newSessions)
+ {
+ session = (MultiThreadSocketSessionImpl) newSessions.peek();
+ }
+
+ if (session == null)
+ {
+ break;
+ }
+
+ SocketChannel ch = session.getChannel();
+
+ try
+ {
+ ch.configureBlocking(false);
+ synchronized (flushingSessionsSet)
+ {
+ flushingSessionsSet.add(session);
+ }
+
+ session.setWriteSelectionKey(ch.register(writeSelector,
+ SelectionKey.OP_WRITE,
+ session));
+
+ //System.out.println("WriteDebug:"+"Awaiting Registration");
+ session.awaitRegistration();
+ sessionCreated(session);
+ }
+ catch (IOException e)
+ {
+
+ // Clear the AbstractIoFilterChain.CONNECT_FUTURE attribute
+ // and call ConnectFuture.setException().
+ session.getFilterChain().fireExceptionCaught(session, e);
+ }
+ }
+ }
+
+
+ private void sessionCreated(SocketSessionImpl sessionParam) throws InterruptedException
+ {
+ MultiThreadSocketSessionImpl session = (MultiThreadSocketSessionImpl) sessionParam;
+ synchronized (newSessions)
+ {
+ if (!session.created())
+ {
+ _logger.debug("Popping new session");
+ newSessions.pop();
+
+ // AbstractIoFilterChain.CONNECT_FUTURE is cleared inside here
+ // in AbstractIoFilterChain.fireSessionOpened().
+ session.getServiceListeners().fireSessionCreated(session);
+
+ session.doneCreation();
+ }
+ }
+ }
+
+ private void doRemove()
+ {
+ if (removingSessions.isEmpty())
+ {
+ return;
+ }
+
+ for (; ;)
+ {
+ MultiThreadSocketSessionImpl session;
+
+ synchronized (removingSessions)
+ {
+ session = (MultiThreadSocketSessionImpl) removingSessions.pop();
+ }
+
+ if (session == null)
+ {
+ break;
+ }
+
+ SocketChannel ch = session.getChannel();
+ SelectionKey key = session.getReadSelectionKey();
+ SelectionKey writeKey = session.getWriteSelectionKey();
+
+ // Retry later if session is not yet fully initialized.
+ // (In case that Session.close() is called before addSession() is processed)
+ if (key == null || writeKey == null)
+ {
+ scheduleRemove(session);
+ break;
+ }
+ // skip if channel is already closed
+ if (!key.isValid() || !writeKey.isValid())
+ {
+ continue;
+ }
+
+ try
+ {
+ //System.out.println("ReadDebug:"+"Removing Session: " + System.identityHashCode(session));
+ synchronized (readLock)
+ {
+ key.cancel();
+ }
+ synchronized (writeLock)
+ {
+ writeKey.cancel();
+ }
+ ch.close();
+ }
+ catch (IOException e)
+ {
+ session.getFilterChain().fireExceptionCaught(session, e);
+ }
+ finally
+ {
+ releaseWriteBuffers(session);
+ session.getServiceListeners().fireSessionDestroyed(session);
+ }
+ }
+ }
+
+ private void processRead(Set selectedKeys)
+ {
+ Iterator it = selectedKeys.iterator();
+
+ while (it.hasNext())
+ {
+ SelectionKey key = (SelectionKey) it.next();
+ MultiThreadSocketSessionImpl session = (MultiThreadSocketSessionImpl) key.attachment();
+
+ synchronized (readLock)
+ {
+ if (key.isValid() && key.isReadable() && session.getTrafficMask().isReadable())
+ {
+ read(session);
+ }
+ }
+
+ }
+
+ selectedKeys.clear();
+ }
+
+ private void processWrite(Set selectedKeys)
+ {
+ Iterator it = selectedKeys.iterator();
+
+ while (it.hasNext())
+ {
+ SelectionKey key = (SelectionKey) it.next();
+ SocketSessionImpl session = (SocketSessionImpl) key.attachment();
+
+ synchronized (writeLock)
+ {
+ if (key.isValid() && key.isWritable() && session.getTrafficMask().isWritable())
+ {
+
+ // Clear OP_WRITE
+ key.interestOps(key.interestOps() & (~SelectionKey.OP_WRITE));
+
+ synchronized (flushingSessionsSet)
+ {
+ flushingSessions.offer(session);
+ }
+ }
+ }
+ }
+
+ selectedKeys.clear();
+ }
+
+ private void read(SocketSessionImpl session)
+ {
+
+ //if (_loggerWrite.isDebugEnabled())
+ {
+ //System.out.println("WriteDebug:"+"Starting read for Session:" + System.identityHashCode(session));
+ }
+
+ int totalReadBytes = 0;
+
+ while (totalReadBytes <= MAX_READ_BYTES_PER_SESSION)
+ {
+ ByteBuffer buf = ByteBuffer.allocate(session.getReadBufferSize());
+ SocketChannel ch = session.getChannel();
+
+ try
+ {
+ buf.clear();
+
+ int readBytes = 0;
+ int ret;
+
+ try
+ {
+ while ((ret = ch.read(buf.buf())) > 0)
+ {
+ readBytes += ret;
+ totalReadBytes += ret;
+ }
+ }
+ finally
+ {
+ buf.flip();
+ }
+
+
+ if (readBytes > 0)
+ {
+ session.increaseReadBytes(readBytes);
+
+ session.getFilterChain().fireMessageReceived(session, buf);
+ buf = null;
+ }
+
+ if (ret <= 0)
+ {
+ if (ret == 0)
+ {
+ if (readBytes == session.getReadBufferSize())
+ {
+ continue;
+ }
+ }
+ else
+ {
+ scheduleRemove(session);
+ }
+
+ break;
+ }
+ }
+ catch (Throwable e)
+ {
+ if (e instanceof IOException)
+ {
+ scheduleRemove(session);
+ }
+ session.getFilterChain().fireExceptionCaught(session, e);
+
+ //Stop Reading this session.
+ return;
+ }
+ finally
+ {
+ if (buf != null)
+ {
+ buf.release();
+ }
+ }
+ }//for
+
+ // if (_loggerWrite.isDebugEnabled())
+ {
+ //System.out.println("WriteDebug:"+"Read for Session:" + System.identityHashCode(session) + " got: " + totalReadBytes);
+ }
+ }
+
+
+ private void notifyReadIdleness()
+ {
+ // process idle sessions
+ long currentTime = System.currentTimeMillis();
+ if ((currentTime - lastIdleReadCheckTime) >= 1000)
+ {
+ lastIdleReadCheckTime = currentTime;
+ Set keys = selector.keys();
+ if (keys != null)
+ {
+ for (Iterator it = keys.iterator(); it.hasNext();)
+ {
+ SelectionKey key = (SelectionKey) it.next();
+ SocketSessionImpl session = (SocketSessionImpl) key.attachment();
+ notifyReadIdleness(session, currentTime);
+ }
+ }
+ }
+ }
+
+ private void notifyWriteIdleness()
+ {
+ // process idle sessions
+ long currentTime = System.currentTimeMillis();
+ if ((currentTime - lastIdleWriteCheckTime) >= 1000)
+ {
+ lastIdleWriteCheckTime = currentTime;
+ Set keys = writeSelector.keys();
+ if (keys != null)
+ {
+ for (Iterator it = keys.iterator(); it.hasNext();)
+ {
+ SelectionKey key = (SelectionKey) it.next();
+ SocketSessionImpl session = (SocketSessionImpl) key.attachment();
+ notifyWriteIdleness(session, currentTime);
+ }
+ }
+ }
+ }
+
+ private void notifyReadIdleness(SocketSessionImpl session, long currentTime)
+ {
+ notifyIdleness0(
+ session, currentTime,
+ session.getIdleTimeInMillis(IdleStatus.BOTH_IDLE),
+ IdleStatus.BOTH_IDLE,
+ Math.max(session.getLastIoTime(), session.getLastIdleTime(IdleStatus.BOTH_IDLE)));
+ notifyIdleness0(
+ session, currentTime,
+ session.getIdleTimeInMillis(IdleStatus.READER_IDLE),
+ IdleStatus.READER_IDLE,
+ Math.max(session.getLastReadTime(), session.getLastIdleTime(IdleStatus.READER_IDLE)));
+
+ notifyWriteTimeout(session, currentTime, session
+ .getWriteTimeoutInMillis(), session.getLastWriteTime());
+ }
+
+ private void notifyWriteIdleness(SocketSessionImpl session, long currentTime)
+ {
+ notifyIdleness0(
+ session, currentTime,
+ session.getIdleTimeInMillis(IdleStatus.BOTH_IDLE),
+ IdleStatus.BOTH_IDLE,
+ Math.max(session.getLastIoTime(), session.getLastIdleTime(IdleStatus.BOTH_IDLE)));
+ notifyIdleness0(
+ session, currentTime,
+ session.getIdleTimeInMillis(IdleStatus.WRITER_IDLE),
+ IdleStatus.WRITER_IDLE,
+ Math.max(session.getLastWriteTime(), session.getLastIdleTime(IdleStatus.WRITER_IDLE)));
+
+ notifyWriteTimeout(session, currentTime, session
+ .getWriteTimeoutInMillis(), session.getLastWriteTime());
+ }
+
+ private void notifyIdleness0(SocketSessionImpl session, long currentTime,
+ long idleTime, IdleStatus status,
+ long lastIoTime)
+ {
+ if (idleTime > 0 && lastIoTime != 0
+ && (currentTime - lastIoTime) >= idleTime)
+ {
+ session.increaseIdleCount(status);
+ session.getFilterChain().fireSessionIdle(session, status);
+ }
+ }
+
+ private void notifyWriteTimeout(SocketSessionImpl session,
+ long currentTime,
+ long writeTimeout, long lastIoTime)
+ {
+
+ MultiThreadSocketSessionImpl sesh = (MultiThreadSocketSessionImpl) session;
+ SelectionKey key = sesh.getWriteSelectionKey();
+
+ synchronized (writeLock)
+ {
+ if (writeTimeout > 0
+ && (currentTime - lastIoTime) >= writeTimeout
+ && key != null && key.isValid()
+ && (key.interestOps() & SelectionKey.OP_WRITE) != 0)
+ {
+ session.getFilterChain().fireExceptionCaught(session, new WriteTimeoutException());
+ }
+ }
+ }
+
+ private SocketSessionImpl getNextFlushingSession()
+ {
+ return (SocketSessionImpl) flushingSessions.poll();
+ }
+
+ private void releaseSession(SocketSessionImpl session)
+ {
+ synchronized (session.getWriteRequestQueue())
+ {
+ synchronized (flushingSessionsSet)
+ {
+ if (session.getScheduledWriteRequests() > 0)
+ {
+ if (_loggerWrite.isDebugEnabled())
+ {
+ //System.out.println("WriteDebug:"+"Reflush" + System.identityHashCode(session));
+ }
+ flushingSessions.offer(session);
+ }
+ else
+ {
+ if (_loggerWrite.isDebugEnabled())
+ {
+ //System.out.println("WriteDebug:"+"Releasing session " + System.identityHashCode(session));
+ }
+ flushingSessionsSet.remove(session);
+ }
+ }
+ }
+ }
+
+ private void releaseWriteBuffers(SocketSessionImpl session)
+ {
+ Queue writeRequestQueue = session.getWriteRequestQueue();
+ WriteRequest req;
+
+ //Should this be synchronized?
+ synchronized (writeRequestQueue)
+ {
+ while ((req = (WriteRequest) writeRequestQueue.pop()) != null)
+ {
+ try
+ {
+ ((ByteBuffer) req.getMessage()).release();
+ }
+ catch (IllegalStateException e)
+ {
+ session.getFilterChain().fireExceptionCaught(session, e);
+ }
+ finally
+ {
+ req.getFuture().setWritten(false);
+ }
+ }
+ }
+ }
+
+ private void doFlush()
+ {
+ MultiThreadSocketSessionImpl session;
+
+ while ((session = (MultiThreadSocketSessionImpl) getNextFlushingSession()) != null)
+ {
+ if (!session.isConnected())
+ {
+ releaseWriteBuffers(session);
+ releaseSession(session);
+ continue;
+ }
+
+ SelectionKey key = session.getWriteSelectionKey();
+ // Retry later if session is not yet fully initialized.
+ // (In case that Session.write() is called before addSession() is processed)
+ if (key == null)
+ {
+ scheduleFlush(session);
+ releaseSession(session);
+ continue;
+ }
+ // skip if channel is already closed
+ if (!key.isValid())
+ {
+ releaseSession(session);
+ continue;
+ }
+
+ try
+ {
+ if (doFlush(session))
+ {
+ releaseSession(session);
+ }
+ }
+ catch (IOException e)
+ {
+ releaseSession(session);
+ scheduleRemove(session);
+ session.getFilterChain().fireExceptionCaught(session, e);
+ }
+
+ }
+
+ }
+
+ private boolean doFlush(SocketSessionImpl sessionParam) throws IOException
+ {
+ MultiThreadSocketSessionImpl session = (MultiThreadSocketSessionImpl) sessionParam;
+ // Clear OP_WRITE
+ SelectionKey key = session.getWriteSelectionKey();
+ synchronized (writeLock)
+ {
+ key.interestOps(key.interestOps() & (~SelectionKey.OP_WRITE));
+ }
+ SocketChannel ch = session.getChannel();
+ Queue writeRequestQueue = session.getWriteRequestQueue();
+
+ long totalFlushedBytes = 0;
+ while (true)
+ {
+ WriteRequest req;
+
+ synchronized (writeRequestQueue)
+ {
+ req = (WriteRequest) writeRequestQueue.first();
+ }
+
+ if (req == null)
+ {
+ break;
+ }
+
+ ByteBuffer buf = (ByteBuffer) req.getMessage();
+ if (buf.remaining() == 0)
+ {
+ synchronized (writeRequestQueue)
+ {
+ writeRequestQueue.pop();
+ }
+
+ session.increaseWrittenMessages();
+
+ buf.reset();
+ session.getFilterChain().fireMessageSent(session, req);
+ continue;
+ }
+
+
+ int writtenBytes = 0;
+
+ // Reported as DIRMINA-362
+ //note: todo: fixme: Not sure it is important but if we see NoyYetConnected exceptions or 100% CPU in the kernel then this is it.
+ if (key.isWritable())
+ {
+ writtenBytes = ch.write(buf.buf());
+ totalFlushedBytes += writtenBytes;
+ }
+
+ if (writtenBytes > 0)
+ {
+ session.increaseWrittenBytes(writtenBytes);
+ }
+
+ if (buf.hasRemaining() || (totalFlushedBytes <= MAX_FLUSH_BYTES_PER_SESSION))
+ {
+ // Kernel buffer is full
+ synchronized (writeLock)
+ {
+ key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
+ }
+ if (_loggerWrite.isDebugEnabled())
+ {
+ //System.out.println("WriteDebug:"+"Written BF: " + (session.getWrittenBytes() - totalFlushedBytes) + " bytes");
+ }
+ return false;
+ }
+ }
+
+ if (_loggerWrite.isDebugEnabled())
+ {
+ //System.out.println("WriteDebug:"+"Written : " + (session.getWrittenBytes() - totalFlushedBytes) + " bytes");
+ }
+ return true;
+ }
+
+ private void doUpdateTrafficMask()
+ {
+ if (trafficControllingSessions.isEmpty() || trafficMaskUpdateLock.isLocked())
+ {
+ return;
+ }
+
+ // Synchronize over entire operation as this method should be called
+ // from both read and write thread and we don't want the order of the
+ // updates to get changed.
+ trafficMaskUpdateLock.lock();
+ try
+ {
+ for (; ;)
+ {
+ MultiThreadSocketSessionImpl session;
+
+ session = (MultiThreadSocketSessionImpl) trafficControllingSessions.pop();
+
+ if (session == null)
+ {
+ break;
+ }
+
+ SelectionKey key = session.getReadSelectionKey();
+ // Retry later if session is not yet fully initialized.
+ // (In case that Session.suspend??() or session.resume??() is
+ // called before addSession() is processed)
+ if (key == null)
+ {
+ scheduleTrafficControl(session);
+ break;
+ }
+ // skip if channel is already closed
+ if (!key.isValid())
+ {
+ continue;
+ }
+
+ // The normal is OP_READ and, if there are write requests in the
+ // session's write queue, set OP_WRITE to trigger flushing.
+
+ //Sset to Read and Write if there is nothing then the cost
+ // is one loop through the flusher.
+ int ops = SelectionKey.OP_READ;
+
+ // Now mask the preferred ops with the mask of the current session
+ int mask = session.getTrafficMask().getInterestOps();
+ synchronized (readLock)
+ {
+ key.interestOps(ops & mask);
+ }
+ //Change key to the WriteSelection Key
+ key = session.getWriteSelectionKey();
+ if (key != null && key.isValid())
+ {
+ Queue writeRequestQueue = session.getWriteRequestQueue();
+ synchronized (writeRequestQueue)
+ {
+ if (!writeRequestQueue.isEmpty())
+ {
+ ops = SelectionKey.OP_WRITE;
+ synchronized (writeLock)
+ {
+ key.interestOps(ops & mask);
+ }
+ }
+ }
+ }
+ }
+ }
+ finally
+ {
+ trafficMaskUpdateLock.unlock();
+ }
+
+ }
+
+ private class WriteWorker implements Runnable
+ {
+
+ public void run()
+ {
+ Thread.currentThread().setName(MultiThreadSocketIoProcessor.this.threadName + "Writer");
+
+ //System.out.println("WriteDebug:"+"Startup");
+ for (; ;)
+ {
+ try
+ {
+ int nKeys = writeSelector.select(SELECTOR_TIMEOUT);
+
+ doAddNewWrite();
+ doUpdateTrafficMask();
+
+ if (nKeys > 0)
+ {
+ //System.out.println("WriteDebug:"+nKeys + " keys from writeselector");
+ processWrite(writeSelector.selectedKeys());
+ }
+ else
+ {
+ //System.out.println("WriteDebug:"+"No keys from writeselector");
+ }
+
+ doRemove();
+ notifyWriteIdleness();
+
+ if (flushingSessionsSet.size() > 0)
+ {
+ doFlush();
+ }
+
+ if (writeSelector.keys().isEmpty())
+ {
+ synchronized (writeLock)
+ {
+
+ if (writeSelector.keys().isEmpty() && newSessions.isEmpty())
+ {
+ writeWorker = null;
+ try
+ {
+ writeSelector.close();
+ }
+ catch (IOException e)
+ {
+ ExceptionMonitor.getInstance().exceptionCaught(e);
+ }
+ finally
+ {
+ writeSelector = null;
+ }
+
+ break;
+ }
+ }
+ }
+
+ }
+ catch (Throwable t)
+ {
+ ExceptionMonitor.getInstance().exceptionCaught(t);
+
+ try
+ {
+ Thread.sleep(1000);
+ }
+ catch (InterruptedException e1)
+ {
+ ExceptionMonitor.getInstance().exceptionCaught(e1);
+ }
+ }
+ }
+ //System.out.println("WriteDebug:"+"Shutdown");
+ }
+
+ }
+
+ private class ReadWorker implements Runnable
+ {
+
+ public void run()
+ {
+ Thread.currentThread().setName(MultiThreadSocketIoProcessor.this.threadName + "Reader");
+
+ //System.out.println("ReadDebug:"+"Startup");
+ for (; ;)
+ {
+ try
+ {
+ int nKeys = selector.select(SELECTOR_TIMEOUT);
+
+ doAddNewReader();
+ doUpdateTrafficMask();
+
+ if (nKeys > 0)
+ {
+ //System.out.println("ReadDebug:"+nKeys + " keys from selector");
+
+ processRead(selector.selectedKeys());
+ }
+ else
+ {
+ //System.out.println("ReadDebug:"+"No keys from selector");
+ }
+
+
+ doRemove();
+ notifyReadIdleness();
+
+ if (selector.keys().isEmpty())
+ {
+
+ synchronized (readLock)
+ {
+ if (selector.keys().isEmpty() && newSessions.isEmpty())
+ {
+ readWorker = null;
+ try
+ {
+ selector.close();
+ }
+ catch (IOException e)
+ {
+ ExceptionMonitor.getInstance().exceptionCaught(e);
+ }
+ finally
+ {
+ selector = null;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ catch (Throwable t)
+ {
+ ExceptionMonitor.getInstance().exceptionCaught(t);
+
+ try
+ {
+ Thread.sleep(1000);
+ }
+ catch (InterruptedException e1)
+ {
+ ExceptionMonitor.getInstance().exceptionCaught(e1);
+ }
+ }
+ }
+ //System.out.println("ReadDebug:"+"Shutdown");
+ }
+
+ }
+}
diff --git a/java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketSessionConfigImpl.java b/java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketSessionConfigImpl.java
new file mode 100644
index 0000000000..043d4800b6
--- /dev/null
+++ b/java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketSessionConfigImpl.java
@@ -0,0 +1,240 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.mina.transport.socket.nio;
+
+import org.apache.mina.common.ExceptionMonitor;
+import org.apache.mina.common.IoConnectorConfig;
+import org.apache.mina.common.support.BaseIoSessionConfig;
+
+import java.io.IOException;
+import java.net.Socket;
+import java.net.SocketException;
+
+/**
+ * An {@link IoConnectorConfig} for {@link SocketConnector}.
+ *
+ * @author The Apache Directory Project (mina-dev@directory.apache.org)
+ * @version $Rev: 619823 $, $Date: 2008-02-08 10:09:37 +0000 (Fri, 08 Feb 2008) $
+ */
+public class MultiThreadSocketSessionConfigImpl extends org.apache.mina.transport.socket.nio.SocketSessionConfigImpl
+{
+ private static boolean SET_RECEIVE_BUFFER_SIZE_AVAILABLE = false;
+ private static boolean SET_SEND_BUFFER_SIZE_AVAILABLE = false;
+ private static boolean GET_TRAFFIC_CLASS_AVAILABLE = false;
+ private static boolean SET_TRAFFIC_CLASS_AVAILABLE = false;
+
+ private static boolean DEFAULT_REUSE_ADDRESS;
+ private static int DEFAULT_RECEIVE_BUFFER_SIZE;
+ private static int DEFAULT_SEND_BUFFER_SIZE;
+ private static int DEFAULT_TRAFFIC_CLASS;
+ private static boolean DEFAULT_KEEP_ALIVE;
+ private static boolean DEFAULT_OOB_INLINE;
+ private static int DEFAULT_SO_LINGER;
+ private static boolean DEFAULT_TCP_NO_DELAY;
+
+ static
+ {
+ initialize();
+ }
+
+ private static void initialize()
+ {
+ Socket socket = null;
+
+ socket = new Socket();
+
+ try
+ {
+ DEFAULT_REUSE_ADDRESS = socket.getReuseAddress();
+ DEFAULT_RECEIVE_BUFFER_SIZE = socket.getReceiveBufferSize();
+ DEFAULT_SEND_BUFFER_SIZE = socket.getSendBufferSize();
+ DEFAULT_KEEP_ALIVE = socket.getKeepAlive();
+ DEFAULT_OOB_INLINE = socket.getOOBInline();
+ DEFAULT_SO_LINGER = socket.getSoLinger();
+ DEFAULT_TCP_NO_DELAY = socket.getTcpNoDelay();
+
+ // Check if setReceiveBufferSize is supported.
+ try
+ {
+ socket.setReceiveBufferSize(DEFAULT_RECEIVE_BUFFER_SIZE);
+ SET_RECEIVE_BUFFER_SIZE_AVAILABLE = true;
+ }
+ catch( SocketException e )
+ {
+ SET_RECEIVE_BUFFER_SIZE_AVAILABLE = false;
+ }
+
+ // Check if setSendBufferSize is supported.
+ try
+ {
+ socket.setSendBufferSize(DEFAULT_SEND_BUFFER_SIZE);
+ SET_SEND_BUFFER_SIZE_AVAILABLE = true;
+ }
+ catch( SocketException e )
+ {
+ SET_SEND_BUFFER_SIZE_AVAILABLE = false;
+ }
+
+ // Check if getTrafficClass is supported.
+ try
+ {
+ DEFAULT_TRAFFIC_CLASS = socket.getTrafficClass();
+ GET_TRAFFIC_CLASS_AVAILABLE = true;
+ }
+ catch( SocketException e )
+ {
+ GET_TRAFFIC_CLASS_AVAILABLE = false;
+ DEFAULT_TRAFFIC_CLASS = 0;
+ }
+ }
+ catch( SocketException e )
+ {
+ throw new ExceptionInInitializerError(e);
+ }
+ finally
+ {
+ if( socket != null )
+ {
+ try
+ {
+ socket.close();
+ }
+ catch( IOException e )
+ {
+ ExceptionMonitor.getInstance().exceptionCaught(e);
+ }
+ }
+ }
+ }
+
+ public static boolean isSetReceiveBufferSizeAvailable() {
+ return SET_RECEIVE_BUFFER_SIZE_AVAILABLE;
+ }
+
+ public static boolean isSetSendBufferSizeAvailable() {
+ return SET_SEND_BUFFER_SIZE_AVAILABLE;
+ }
+
+ public static boolean isGetTrafficClassAvailable() {
+ return GET_TRAFFIC_CLASS_AVAILABLE;
+ }
+
+ public static boolean isSetTrafficClassAvailable() {
+ return SET_TRAFFIC_CLASS_AVAILABLE;
+ }
+
+ private boolean reuseAddress = DEFAULT_REUSE_ADDRESS;
+ private int receiveBufferSize = DEFAULT_RECEIVE_BUFFER_SIZE;
+ private int sendBufferSize = DEFAULT_SEND_BUFFER_SIZE;
+ private int trafficClass = DEFAULT_TRAFFIC_CLASS;
+ private boolean keepAlive = DEFAULT_KEEP_ALIVE;
+ private boolean oobInline = DEFAULT_OOB_INLINE;
+ private int soLinger = DEFAULT_SO_LINGER;
+ private boolean tcpNoDelay = DEFAULT_TCP_NO_DELAY;
+
+ /**
+ * Creates a new instance.
+ */
+ MultiThreadSocketSessionConfigImpl()
+ {
+ }
+
+ public boolean isReuseAddress()
+ {
+ return reuseAddress;
+ }
+
+ public void setReuseAddress( boolean reuseAddress )
+ {
+ this.reuseAddress = reuseAddress;
+ }
+
+ public int getReceiveBufferSize()
+ {
+ return receiveBufferSize;
+ }
+
+ public void setReceiveBufferSize( int receiveBufferSize )
+ {
+ this.receiveBufferSize = receiveBufferSize;
+ }
+
+ public int getSendBufferSize()
+ {
+ return sendBufferSize;
+ }
+
+ public void setSendBufferSize( int sendBufferSize )
+ {
+ this.sendBufferSize = sendBufferSize;
+ }
+
+ public int getTrafficClass()
+ {
+ return trafficClass;
+ }
+
+ public void setTrafficClass( int trafficClass )
+ {
+ this.trafficClass = trafficClass;
+ }
+
+ public boolean isKeepAlive()
+ {
+ return keepAlive;
+ }
+
+ public void setKeepAlive( boolean keepAlive )
+ {
+ this.keepAlive = keepAlive;
+ }
+
+ public boolean isOobInline()
+ {
+ return oobInline;
+ }
+
+ public void setOobInline( boolean oobInline )
+ {
+ this.oobInline = oobInline;
+ }
+
+ public int getSoLinger()
+ {
+ return soLinger;
+ }
+
+ public void setSoLinger( int soLinger )
+ {
+ this.soLinger = soLinger;
+ }
+
+ public boolean isTcpNoDelay()
+ {
+ return tcpNoDelay;
+ }
+
+ public void setTcpNoDelay( boolean tcpNoDelay )
+ {
+ this.tcpNoDelay = tcpNoDelay;
+ }
+
+
+}
diff --git a/java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketSessionImpl.java b/java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketSessionImpl.java
new file mode 100644
index 0000000000..be4a2d289d
--- /dev/null
+++ b/java/common/src/main/java/org/apache/mina/transport/socket/nio/MultiThreadSocketSessionImpl.java
@@ -0,0 +1,488 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.mina.transport.socket.nio;
+
+import org.apache.mina.common.IoFilter.WriteRequest;
+import org.apache.mina.common.IoFilterChain;
+import org.apache.mina.common.IoHandler;
+import org.apache.mina.common.IoService;
+import org.apache.mina.common.IoServiceConfig;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.common.IoSessionConfig;
+import org.apache.mina.common.RuntimeIOException;
+import org.apache.mina.common.TransportType;
+import org.apache.mina.common.support.BaseIoSessionConfig;
+import org.apache.mina.common.support.IoServiceListenerSupport;
+import org.apache.mina.util.Queue;
+
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.SocketChannel;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * An {@link IoSession} for socket transport (TCP/IP).
+ *
+ * @author The Apache Directory Project (mina-dev@directory.apache.org)
+ * @version $Rev: 619823 $, $Date: 2008-02-08 10:09:37 +0000 (Fri, 08 Feb 2008) $
+ */
+class MultiThreadSocketSessionImpl extends SocketSessionImpl
+{
+ private final IoService manager;
+ private final IoServiceConfig serviceConfig;
+ private final SocketSessionConfig config = new SessionConfigImpl();
+ private final MultiThreadSocketIoProcessor ioProcessor;
+ private final MultiThreadSocketFilterChain filterChain;
+ private final SocketChannel ch;
+ private final Queue writeRequestQueue;
+ private final IoHandler handler;
+ private final SocketAddress remoteAddress;
+ private final SocketAddress localAddress;
+ private final SocketAddress serviceAddress;
+ private final IoServiceListenerSupport serviceListeners;
+ private SelectionKey readKey, writeKey;
+ private int readBufferSize;
+ private CountDownLatch registeredReadyLatch = new CountDownLatch(2);
+ private AtomicBoolean created = new AtomicBoolean(false);
+
+ /**
+ * Creates a new instance.
+ */
+ MultiThreadSocketSessionImpl( IoService manager,
+ SocketIoProcessor ioProcessor,
+ IoServiceListenerSupport listeners,
+ IoServiceConfig serviceConfig,
+ SocketChannel ch,
+ IoHandler defaultHandler,
+ SocketAddress serviceAddress )
+ {
+ super(manager, ioProcessor, listeners, serviceConfig, ch,defaultHandler,serviceAddress);
+ this.manager = manager;
+ this.serviceListeners = listeners;
+ this.ioProcessor = (MultiThreadSocketIoProcessor) ioProcessor;
+ this.filterChain = new MultiThreadSocketFilterChain(this);
+ this.ch = ch;
+ this.writeRequestQueue = new Queue();
+ this.handler = defaultHandler;
+ this.remoteAddress = ch.socket().getRemoteSocketAddress();
+ this.localAddress = ch.socket().getLocalSocketAddress();
+ this.serviceAddress = serviceAddress;
+ this.serviceConfig = serviceConfig;
+
+ // Apply the initial session settings
+ IoSessionConfig sessionConfig = serviceConfig.getSessionConfig();
+ if( sessionConfig instanceof SocketSessionConfig )
+ {
+ SocketSessionConfig cfg = ( SocketSessionConfig ) sessionConfig;
+ this.config.setKeepAlive( cfg.isKeepAlive() );
+ this.config.setOobInline( cfg.isOobInline() );
+ this.config.setReceiveBufferSize( cfg.getReceiveBufferSize() );
+ this.readBufferSize = cfg.getReceiveBufferSize();
+ this.config.setReuseAddress( cfg.isReuseAddress() );
+ this.config.setSendBufferSize( cfg.getSendBufferSize() );
+ this.config.setSoLinger( cfg.getSoLinger() );
+ this.config.setTcpNoDelay( cfg.isTcpNoDelay() );
+
+ if( this.config.getTrafficClass() != cfg.getTrafficClass() )
+ {
+ this.config.setTrafficClass( cfg.getTrafficClass() );
+ }
+ }
+ }
+
+ void awaitRegistration() throws InterruptedException
+ {
+ registeredReadyLatch.countDown();
+
+ registeredReadyLatch.await();
+ }
+
+ boolean created() throws InterruptedException
+ {
+ return created.get();
+ }
+
+ void doneCreation()
+ {
+ created.getAndSet(true);
+ }
+
+ public IoService getService()
+ {
+ return manager;
+ }
+
+ public IoServiceConfig getServiceConfig()
+ {
+ return serviceConfig;
+ }
+
+ public IoSessionConfig getConfig()
+ {
+ return config;
+ }
+
+ SocketIoProcessor getIoProcessor()
+ {
+ return ioProcessor;
+ }
+
+ public IoFilterChain getFilterChain()
+ {
+ return filterChain;
+ }
+
+ SocketChannel getChannel()
+ {
+ return ch;
+ }
+
+ IoServiceListenerSupport getServiceListeners()
+ {
+ return serviceListeners;
+ }
+
+ SelectionKey getSelectionKey()
+ {
+ return readKey;
+ }
+
+ SelectionKey getReadSelectionKey()
+ {
+ return readKey;
+ }
+
+ SelectionKey getWriteSelectionKey()
+ {
+ return writeKey;
+ }
+
+ void setSelectionKey(SelectionKey key)
+ {
+ this.readKey = key;
+ }
+
+ void setWriteSelectionKey(SelectionKey key)
+ {
+ this.writeKey = key;
+ }
+
+ public IoHandler getHandler()
+ {
+ return handler;
+ }
+
+ protected void close0()
+ {
+ filterChain.fireFilterClose( this );
+ }
+
+ Queue getWriteRequestQueue()
+ {
+ return writeRequestQueue;
+ }
+
+ /**
+ @return int Number of write scheduled write requests
+ @deprecated
+ */
+ public int getScheduledWriteMessages()
+ {
+ return getScheduledWriteRequests();
+ }
+
+ public int getScheduledWriteRequests()
+ {
+ synchronized( writeRequestQueue )
+ {
+ return writeRequestQueue.size();
+ }
+ }
+
+ public int getScheduledWriteBytes()
+ {
+ synchronized( writeRequestQueue )
+ {
+ return writeRequestQueue.byteSize();
+ }
+ }
+
+ protected void write0( WriteRequest writeRequest )
+ {
+ filterChain.fireFilterWrite( this, writeRequest );
+ }
+
+ public TransportType getTransportType()
+ {
+ return TransportType.SOCKET;
+ }
+
+ public SocketAddress getRemoteAddress()
+ {
+ //This is what I had previously
+// return ch.socket().getRemoteSocketAddress();
+ return remoteAddress;
+ }
+
+ public SocketAddress getLocalAddress()
+ {
+ //This is what I had previously
+// return ch.socket().getLocalSocketAddress();
+ return localAddress;
+ }
+
+ public SocketAddress getServiceAddress()
+ {
+ return serviceAddress;
+ }
+
+ protected void updateTrafficMask()
+ {
+ this.ioProcessor.updateTrafficMask( this );
+ }
+
+ int getReadBufferSize()
+ {
+ return readBufferSize;
+ }
+
+ private class SessionConfigImpl extends BaseIoSessionConfig implements SocketSessionConfig
+ {
+ public boolean isKeepAlive()
+ {
+ try
+ {
+ return ch.socket().getKeepAlive();
+ }
+ catch( SocketException e )
+ {
+ throw new RuntimeIOException( e );
+ }
+ }
+
+ public void setKeepAlive( boolean on )
+ {
+ try
+ {
+ ch.socket().setKeepAlive( on );
+ }
+ catch( SocketException e )
+ {
+ throw new RuntimeIOException( e );
+ }
+ }
+
+ public boolean isOobInline()
+ {
+ try
+ {
+ return ch.socket().getOOBInline();
+ }
+ catch( SocketException e )
+ {
+ throw new RuntimeIOException( e );
+ }
+ }
+
+ public void setOobInline( boolean on )
+ {
+ try
+ {
+ ch.socket().setOOBInline( on );
+ }
+ catch( SocketException e )
+ {
+ throw new RuntimeIOException( e );
+ }
+ }
+
+ public boolean isReuseAddress()
+ {
+ try
+ {
+ return ch.socket().getReuseAddress();
+ }
+ catch( SocketException e )
+ {
+ throw new RuntimeIOException( e );
+ }
+ }
+
+ public void setReuseAddress( boolean on )
+ {
+ try
+ {
+ ch.socket().setReuseAddress( on );
+ }
+ catch( SocketException e )
+ {
+ throw new RuntimeIOException( e );
+ }
+ }
+
+ public int getSoLinger()
+ {
+ try
+ {
+ return ch.socket().getSoLinger();
+ }
+ catch( SocketException e )
+ {
+ throw new RuntimeIOException( e );
+ }
+ }
+
+ public void setSoLinger( int linger )
+ {
+ try
+ {
+ if( linger < 0 )
+ {
+ ch.socket().setSoLinger( false, 0 );
+ }
+ else
+ {
+ ch.socket().setSoLinger( true, linger );
+ }
+ }
+ catch( SocketException e )
+ {
+ throw new RuntimeIOException( e );
+ }
+ }
+
+ public boolean isTcpNoDelay()
+ {
+ try
+ {
+ return ch.socket().getTcpNoDelay();
+ }
+ catch( SocketException e )
+ {
+ throw new RuntimeIOException( e );
+ }
+ }
+
+ public void setTcpNoDelay( boolean on )
+ {
+ try
+ {
+ ch.socket().setTcpNoDelay( on );
+ }
+ catch( SocketException e )
+ {
+ throw new RuntimeIOException( e );
+ }
+ }
+
+ public int getTrafficClass()
+ {
+ if( SocketSessionConfigImpl.isGetTrafficClassAvailable() )
+ {
+ try
+ {
+ return ch.socket().getTrafficClass();
+ }
+ catch( SocketException e )
+ {
+ // Throw an exception only when setTrafficClass is also available.
+ if( SocketSessionConfigImpl.isSetTrafficClassAvailable() )
+ {
+ throw new RuntimeIOException( e );
+ }
+ }
+ }
+
+ return 0;
+ }
+
+ public void setTrafficClass( int tc )
+ {
+ if( SocketSessionConfigImpl.isSetTrafficClassAvailable() )
+ {
+ try
+ {
+ ch.socket().setTrafficClass( tc );
+ }
+ catch( SocketException e )
+ {
+ throw new RuntimeIOException( e );
+ }
+ }
+ }
+
+ public int getSendBufferSize()
+ {
+ try
+ {
+ return ch.socket().getSendBufferSize();
+ }
+ catch( SocketException e )
+ {
+ throw new RuntimeIOException( e );
+ }
+ }
+
+ public void setSendBufferSize( int size )
+ {
+ if( SocketSessionConfigImpl.isSetSendBufferSizeAvailable() )
+ {
+ try
+ {
+ ch.socket().setSendBufferSize( size );
+ }
+ catch( SocketException e )
+ {
+ throw new RuntimeIOException( e );
+ }
+ }
+ }
+
+ public int getReceiveBufferSize()
+ {
+ try
+ {
+ return ch.socket().getReceiveBufferSize();
+ }
+ catch( SocketException e )
+ {
+ throw new RuntimeIOException( e );
+ }
+ }
+
+ public void setReceiveBufferSize( int size )
+ {
+ if( SocketSessionConfigImpl.isSetReceiveBufferSizeAvailable() )
+ {
+ try
+ {
+ ch.socket().setReceiveBufferSize( size );
+ MultiThreadSocketSessionImpl.this.readBufferSize = size;
+ }
+ catch( SocketException e )
+ {
+ throw new RuntimeIOException( e );
+ }
+ }
+ }
+ }
+}
diff --git a/java/common/src/main/java/org/apache/mina/transport/vmpipe/QpidVmPipeConnector.java b/java/common/src/main/java/org/apache/mina/transport/vmpipe/QpidVmPipeConnector.java
new file mode 100644
index 0000000000..a23e546af5
--- /dev/null
+++ b/java/common/src/main/java/org/apache/mina/transport/vmpipe/QpidVmPipeConnector.java
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.mina.transport.vmpipe;
+
+import java.io.IOException;
+import java.net.SocketAddress;
+
+import org.apache.mina.common.ConnectFuture;
+import org.apache.mina.common.ExceptionMonitor;
+import org.apache.mina.common.IoFilterChain;
+import org.apache.mina.common.IoHandler;
+import org.apache.mina.common.IoServiceConfig;
+import org.apache.mina.common.IoSessionConfig;
+import org.apache.mina.common.support.AbstractIoFilterChain;
+import org.apache.mina.common.support.BaseIoConnector;
+import org.apache.mina.common.support.BaseIoConnectorConfig;
+import org.apache.mina.common.support.BaseIoSessionConfig;
+import org.apache.mina.common.support.DefaultConnectFuture;
+import org.apache.mina.transport.vmpipe.support.VmPipe;
+import org.apache.mina.transport.vmpipe.support.VmPipeIdleStatusChecker;
+import org.apache.mina.transport.vmpipe.support.VmPipeSessionImpl;
+import org.apache.mina.util.AnonymousSocketAddress;
+
+/**
+ * Connects to {@link IoHandler}s which is bound on the specified
+ * {@link VmPipeAddress}.
+ *
+ * @author The Apache Directory Project (mina-dev@directory.apache.org)
+ * @version $Rev: 619823 $, $Date: 2008-02-08 10:09:37 +0000 (Fri, 08 Feb 2008) $
+ */
+public class QpidVmPipeConnector extends VmPipeConnector
+{
+ private static final IoSessionConfig CONFIG = new BaseIoSessionConfig() {};
+ private final IoServiceConfig defaultConfig = new BaseIoConnectorConfig()
+ {
+ public IoSessionConfig getSessionConfig()
+ {
+ return CONFIG;
+ }
+ };
+
+ /**
+ * Creates a new instance.
+ */
+ public QpidVmPipeConnector()
+ {
+ }
+
+ public ConnectFuture connect( SocketAddress address, IoHandler handler, IoServiceConfig config )
+ {
+ return connect( address, null, handler, config );
+ }
+
+ public ConnectFuture connect( SocketAddress address, SocketAddress localAddress, IoHandler handler, IoServiceConfig config )
+ {
+ if( address == null )
+ throw new NullPointerException( "address" );
+ if( handler == null )
+ throw new NullPointerException( "handler" );
+ if( ! ( address instanceof VmPipeAddress ) )
+ throw new IllegalArgumentException(
+ "address must be VmPipeAddress." );
+
+ if( config == null )
+ {
+ config = getDefaultConfig();
+ }
+
+ VmPipe entry = ( VmPipe ) VmPipeAcceptor.boundHandlers.get( address );
+ if( entry == null )
+ {
+ return DefaultConnectFuture.newFailedFuture(
+ new IOException( "Endpoint unavailable: " + address ) );
+ }
+
+ DefaultConnectFuture future = new DefaultConnectFuture();
+ VmPipeSessionImpl localSession =
+ new VmPipeSessionImpl(
+ this,
+ config,
+ getListeners(),
+ new Object(), // lock
+ new AnonymousSocketAddress(),
+ handler,
+ entry );
+
+ // initialize acceptor session
+ VmPipeSessionImpl remoteSession = localSession.getRemoteSession();
+ try
+ {
+ IoFilterChain filterChain = remoteSession.getFilterChain();
+ entry.getAcceptor().getFilterChainBuilder().buildFilterChain( filterChain );
+ entry.getConfig().getFilterChainBuilder().buildFilterChain( filterChain );
+ entry.getConfig().getThreadModel().buildFilterChain( filterChain );
+
+ // The following sentences don't throw any exceptions.
+ entry.getListeners().fireSessionCreated( remoteSession );
+ VmPipeIdleStatusChecker.getInstance().addSession( remoteSession );
+ }
+ catch( Throwable t )
+ {
+ ExceptionMonitor.getInstance().exceptionCaught( t );
+ remoteSession.close();
+ }
+
+
+ // initialize connector session
+ try
+ {
+ IoFilterChain filterChain = localSession.getFilterChain();
+ this.getFilterChainBuilder().buildFilterChain( filterChain );
+ config.getFilterChainBuilder().buildFilterChain( filterChain );
+ config.getThreadModel().buildFilterChain( filterChain );
+
+ // The following sentences don't throw any exceptions.
+ localSession.setAttribute( AbstractIoFilterChain.CONNECT_FUTURE, future );
+ getListeners().fireSessionCreated( localSession );
+ VmPipeIdleStatusChecker.getInstance().addSession( localSession);
+ }
+ catch( Throwable t )
+ {
+ future.setException( t );
+ }
+
+
+
+ return future;
+ }
+
+ public IoServiceConfig getDefaultConfig()
+ {
+ return defaultConfig;
+ }
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/AMQChannelException.java b/java/common/src/main/java/org/apache/qpid/AMQChannelException.java
index 2f6290b55a..ef9420ba87 100644
--- a/java/common/src/main/java/org/apache/qpid/AMQChannelException.java
+++ b/java/common/src/main/java/org/apache/qpid/AMQChannelException.java
@@ -54,7 +54,6 @@ public class AMQChannelException extends AMQException
public AMQFrame getCloseFrame(int channel)
{
MethodRegistry reg = MethodRegistry.getMethodRegistry(new ProtocolVersion(major,minor));
- return new AMQFrame(channel, reg.createChannelCloseBody(getErrorCode() == null ? AMQConstant.INTERNAL_ERROR.getCode() : getErrorCode().getCode(), getMessageAsShortString(),_classId,_methodId));
+ return new AMQFrame(channel, reg.createChannelCloseBody(getErrorCode() == null ? AMQConstant.INTERNAL_ERROR.getCode() : getErrorCode().getCode(), new AMQShortString(getMessage()),_classId,_methodId));
}
-
}
diff --git a/java/common/src/main/java/org/apache/qpid/AMQConnectionException.java b/java/common/src/main/java/org/apache/qpid/AMQConnectionException.java
index ca9c9f9dc4..8ef6facef1 100644
--- a/java/common/src/main/java/org/apache/qpid/AMQConnectionException.java
+++ b/java/common/src/main/java/org/apache/qpid/AMQConnectionException.java
@@ -62,10 +62,9 @@ public class AMQConnectionException extends AMQException
MethodRegistry reg = MethodRegistry.getMethodRegistry(new ProtocolVersion(major,minor));
return new AMQFrame(0,
reg.createConnectionCloseBody(getErrorCode().getCode(),
- getMessageAsShortString(),
+ new AMQShortString(getMessage()),
_classId,
_methodId));
}
-
}
diff --git a/java/common/src/main/java/org/apache/qpid/AMQException.java b/java/common/src/main/java/org/apache/qpid/AMQException.java
index 86d439d269..b0c6fccc9e 100644
--- a/java/common/src/main/java/org/apache/qpid/AMQException.java
+++ b/java/common/src/main/java/org/apache/qpid/AMQException.java
@@ -20,7 +20,6 @@
*/
package org.apache.qpid;
-import org.apache.qpid.framing.AMQShortString;
import org.apache.qpid.protocol.AMQConstant;
/**
@@ -122,19 +121,4 @@ public class AMQException extends Exception
return newAMQE;
}
-
- /**
- * Truncates the exception message to 255 characters if its length exceeds 255.
- *
- * @return exception message
- */
- public AMQShortString getMessageAsShortString()
- {
- String message = getMessage();
- if (message != null && message.length() > AMQShortString.MAX_LENGTH)
- {
- message = message.substring(0, AMQShortString.MAX_LENGTH - 3) + "...";
- }
- return new AMQShortString(message);
- }
}
diff --git a/java/common/src/main/java/org/apache/qpid/AMQInvalidArgumentException.java b/java/common/src/main/java/org/apache/qpid/AMQInvalidArgumentException.java
index 2bbaaef1fc..baca2a4773 100644
--- a/java/common/src/main/java/org/apache/qpid/AMQInvalidArgumentException.java
+++ b/java/common/src/main/java/org/apache/qpid/AMQInvalidArgumentException.java
@@ -34,7 +34,7 @@ public class AMQInvalidArgumentException extends AMQException
{
public AMQInvalidArgumentException(String message, Throwable cause)
{
- super(AMQConstant.ARGUMENT_INVALID, message, cause);
+ super(AMQConstant.INVALID_ARGUMENT, message, cause);
}
public boolean isHardError()
diff --git a/java/common/src/main/java/org/apache/qpid/ToyBroker.java b/java/common/src/main/java/org/apache/qpid/ToyBroker.java
new file mode 100644
index 0000000000..5423bbb68f
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/ToyBroker.java
@@ -0,0 +1,208 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid;
+
+import org.apache.qpid.transport.*;
+import org.apache.qpid.transport.network.mina.MinaHandler;
+
+import static org.apache.qpid.transport.util.Functions.str;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.LinkedBlockingQueue;
+
+
+/**
+ * ToyBroker
+ *
+ * @author Rafael H. Schloming
+ */
+
+class ToyBroker extends SessionDelegate
+{
+
+ private ToyExchange exchange;
+ private Map<String,Consumer> consumers = new ConcurrentHashMap<String,Consumer>();
+
+ public ToyBroker(ToyExchange exchange)
+ {
+ this.exchange = exchange;
+ }
+
+ public void messageAcquire(Session context, MessageAcquire struct)
+ {
+ System.out.println("\n==================> messageAcquire " );
+ context.executionResult((int) struct.getId(), new Acquired(struct.getTransfers()));
+ }
+
+ @Override public void queueDeclare(Session ssn, QueueDeclare qd)
+ {
+ exchange.createQueue(qd.getQueue());
+ System.out.println("\n==================> declared queue: " + qd.getQueue() + "\n");
+ }
+
+ @Override public void exchangeBind(Session ssn, ExchangeBind qb)
+ {
+ exchange.bindQueue(qb.getExchange(), qb.getBindingKey(),qb.getQueue());
+ System.out.println("\n==================> bound queue: " + qb.getQueue() + " with binding key " + qb.getBindingKey() + "\n");
+ }
+
+ @Override public void queueQuery(Session ssn, QueueQuery qq)
+ {
+ QueueQueryResult result = new QueueQueryResult().queue(qq.getQueue());
+ ssn.executionResult((int) qq.getId(), result);
+ }
+
+ @Override public void messageSubscribe(Session ssn, MessageSubscribe ms)
+ {
+ Consumer c = new Consumer();
+ c._queueName = ms.getQueue();
+ consumers.put(ms.getDestination(),c);
+ System.out.println("\n==================> message subscribe : " + ms.getDestination() + " queue: " + ms.getQueue() + "\n");
+ }
+
+ @Override public void messageFlow(Session ssn,MessageFlow struct)
+ {
+ Consumer c = consumers.get(struct.getDestination());
+ c._credit = struct.getValue();
+ System.out.println("\n==================> message flow : " + struct.getDestination() + " credit: " + struct.getValue() + "\n");
+ }
+
+ @Override public void messageFlush(Session ssn,MessageFlush struct)
+ {
+ System.out.println("\n==================> message flush for consumer : " + struct.getDestination() + "\n");
+ checkAndSendMessagesToConsumer(ssn,struct.getDestination());
+ }
+
+ @Override public void messageTransfer(Session ssn, MessageTransfer xfr)
+ {
+ String dest = xfr.getDestination();
+ System.out.println("received transfer " + dest);
+ Header header = xfr.getHeader();
+ DeliveryProperties props = header.get(DeliveryProperties.class);
+ if (props != null)
+ {
+ System.out.println("received headers routing_key " + props.getRoutingKey());
+ }
+
+ MessageProperties mp = header.get(MessageProperties.class);
+ System.out.println("MP: " + mp);
+ if (mp != null)
+ {
+ System.out.println(mp.getApplicationHeaders());
+ }
+
+ if (exchange.route(dest,props == null ? null : props.getRoutingKey(),xfr))
+ {
+ System.out.println("queued " + xfr);
+ dispatchMessages(ssn);
+ }
+ else
+ {
+
+ if (props == null || !props.getDiscardUnroutable())
+ {
+ RangeSet ranges = new RangeSet();
+ ranges.add(xfr.getId());
+ ssn.messageReject(ranges, MessageRejectCode.UNROUTABLE,
+ "no such destination");
+ }
+ }
+ ssn.processed(xfr);
+ }
+
+ private void transferMessageToPeer(Session ssn,String dest, MessageTransfer m)
+ {
+ System.out.println("\n==================> Transfering message to: " +dest + "\n");
+ ssn.messageTransfer(m.getDestination(), MessageAcceptMode.EXPLICIT,
+ MessageAcquireMode.PRE_ACQUIRED,
+ m.getHeader(), m.getBody());
+ }
+
+ private void dispatchMessages(Session ssn)
+ {
+ for (String dest: consumers.keySet())
+ {
+ checkAndSendMessagesToConsumer(ssn,dest);
+ }
+ }
+
+ private void checkAndSendMessagesToConsumer(Session ssn,String dest)
+ {
+ Consumer c = consumers.get(dest);
+ LinkedBlockingQueue<MessageTransfer> queue = exchange.getQueue(c._queueName);
+ MessageTransfer m = queue.poll();
+ while (m != null && c._credit>0)
+ {
+ transferMessageToPeer(ssn,dest,m);
+ c._credit--;
+ m = queue.poll();
+ }
+ }
+
+ // ugly, but who cares :)
+ // assumes unit is always no of messages, not bytes
+ // assumes it's credit mode and not window
+ private static class Consumer
+ {
+ long _credit;
+ String _queueName;
+ }
+
+ private static final class ToyBrokerSession extends Session
+ {
+
+ public ToyBrokerSession(Connection connection, Binary name, long expiry, ToyExchange exchange)
+ {
+ super(connection, new ToyBroker(exchange), name, expiry);
+ }
+ }
+
+ public static final void main(String[] args) throws IOException
+ {
+ final ToyExchange exchange = new ToyExchange();
+ ConnectionDelegate delegate = new ServerDelegate()
+ {
+ @Override
+ public void init(Connection conn, ProtocolHeader hdr)
+ {
+ conn.setSessionFactory(new Connection.SessionFactory()
+ {
+ public Session newSession(Connection conn, Binary name, long expiry)
+ {
+ return new ToyBrokerSession(conn, name, expiry, exchange);
+ }
+ });
+
+ super.init(conn, hdr); //To change body of overridden methods use File | Settings | File Templates.
+ }
+
+ };
+
+ MinaHandler.accept("0.0.0.0", 5672, delegate);
+ }
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/ToyClient.java b/java/common/src/main/java/org/apache/qpid/ToyClient.java
new file mode 100644
index 0000000000..5b2db10613
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/ToyClient.java
@@ -0,0 +1,108 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid;
+
+import java.nio.*;
+import java.util.*;
+
+import org.apache.qpid.transport.*;
+import org.apache.qpid.transport.network.mina.MinaHandler;
+
+
+/**
+ * ToyClient
+ *
+ * @author Rafael H. Schloming
+ */
+
+class ToyClient implements SessionListener
+{
+ public void opened(Session ssn) {}
+
+ public void resumed(Session ssn) {}
+
+ public void exception(Session ssn, SessionException exc)
+ {
+ exc.printStackTrace();
+ }
+
+ public void message(Session ssn, MessageTransfer xfr)
+ {
+ System.out.println("msg: " + xfr);
+ }
+
+ public void closed(Session ssn) {}
+
+ public static final void main(String[] args)
+ {
+ Connection conn = new Connection();
+ conn.connect("0.0.0.0", 5672, null, "guest", "guest", false);
+ Session ssn = conn.createSession();
+ ssn.setSessionListener(new ToyClient());
+
+ ssn.queueDeclare("asdf", null, null);
+ ssn.sync();
+
+ Map<String,Object> nested = new LinkedHashMap<String,Object>();
+ nested.put("list", Arrays.asList("one", "two", "three"));
+ Map<String,Object> map = new LinkedHashMap<String,Object>();
+
+ map.put("str", "this is a string");
+
+ map.put("+int", 3);
+ map.put("-int", -3);
+ map.put("maxint", Integer.MAX_VALUE);
+ map.put("minint", Integer.MIN_VALUE);
+
+ map.put("+short", (short) 1);
+ map.put("-short", (short) -1);
+ map.put("maxshort", (short) Short.MAX_VALUE);
+ map.put("minshort", (short) Short.MIN_VALUE);
+
+ map.put("float", (float) 3.3);
+ map.put("double", 4.9);
+ map.put("char", 'c');
+
+ map.put("table", nested);
+ map.put("list", Arrays.asList(1, 2, 3));
+ map.put("binary", new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10});
+
+ ssn.messageTransfer("asdf", MessageAcceptMode.EXPLICIT,
+ MessageAcquireMode.PRE_ACQUIRED,
+ new Header(new DeliveryProperties(),
+ new MessageProperties()
+ .setApplicationHeaders(map)),
+ "this is the data");
+
+ ssn.messageTransfer("fdsa", MessageAcceptMode.EXPLICIT,
+ MessageAcquireMode.PRE_ACQUIRED,
+ null,
+ "this should be rejected");
+ ssn.sync();
+
+ Future<QueueQueryResult> future = ssn.queueQuery("asdf");
+ System.out.println(future.get().getQueue());
+ ssn.sync();
+ ssn.close();
+ conn.close();
+ }
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/ToyExchange.java b/java/common/src/main/java/org/apache/qpid/ToyExchange.java
new file mode 100644
index 0000000000..da6aed9629
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/ToyExchange.java
@@ -0,0 +1,154 @@
+package org.apache.qpid;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.qpid.transport.MessageTransfer;
+
+
+public class ToyExchange
+{
+ final static String DIRECT = "amq.direct";
+ final static String TOPIC = "amq.topic";
+
+ private Map<String,List<LinkedBlockingQueue<MessageTransfer>>> directEx = new HashMap<String,List<LinkedBlockingQueue<MessageTransfer>>>();
+ private Map<String,List<LinkedBlockingQueue<MessageTransfer>>> topicEx = new HashMap<String,List<LinkedBlockingQueue<MessageTransfer>>>();
+ private Map<String,LinkedBlockingQueue<MessageTransfer>> queues = new HashMap<String,LinkedBlockingQueue<MessageTransfer>>();
+
+ public void createQueue(String name)
+ {
+ queues.put(name, new LinkedBlockingQueue<MessageTransfer>());
+ }
+
+ public LinkedBlockingQueue<MessageTransfer> getQueue(String name)
+ {
+ return queues.get(name);
+ }
+
+ public void bindQueue(String type,String binding,String queueName)
+ {
+ LinkedBlockingQueue<MessageTransfer> queue = queues.get(queueName);
+ binding = normalizeKey(binding);
+ if(DIRECT.equals(type))
+ {
+
+ if (directEx.containsKey(binding))
+ {
+ List<LinkedBlockingQueue<MessageTransfer>> list = directEx.get(binding);
+ list.add(queue);
+ }
+ else
+ {
+ List<LinkedBlockingQueue<MessageTransfer>> list = new LinkedList<LinkedBlockingQueue<MessageTransfer>>();
+ list.add(queue);
+ directEx.put(binding,list);
+ }
+ }
+ else
+ {
+ if (topicEx.containsKey(binding))
+ {
+ List<LinkedBlockingQueue<MessageTransfer>> list = topicEx.get(binding);
+ list.add(queue);
+ }
+ else
+ {
+ List<LinkedBlockingQueue<MessageTransfer>> list = new LinkedList<LinkedBlockingQueue<MessageTransfer>>();
+ list.add(queue);
+ topicEx.put(binding,list);
+ }
+ }
+ }
+
+ public boolean route(String dest, String routingKey, MessageTransfer msg)
+ {
+ List<LinkedBlockingQueue<MessageTransfer>> queues;
+ if(DIRECT.equals(dest))
+ {
+ queues = directEx.get(routingKey);
+ }
+ else
+ {
+ queues = matchWildCard(routingKey);
+ }
+ if(queues != null && queues.size()>0)
+ {
+ System.out.println("Message stored in " + queues.size() + " queues");
+ storeMessage(msg,queues);
+ return true;
+ }
+ else
+ {
+ System.out.println("Message unroutable " + msg);
+ return false;
+ }
+ }
+
+ private String normalizeKey(String routingKey)
+ {
+ if(routingKey.indexOf(".*")>1)
+ {
+ return routingKey.substring(0,routingKey.indexOf(".*"));
+ }
+ else
+ {
+ return routingKey;
+ }
+ }
+
+ private List<LinkedBlockingQueue<MessageTransfer>> matchWildCard(String routingKey)
+ {
+ List<LinkedBlockingQueue<MessageTransfer>> selected = new ArrayList<LinkedBlockingQueue<MessageTransfer>>();
+
+ for(String key: topicEx.keySet())
+ {
+ Pattern p = Pattern.compile(key);
+ Matcher m = p.matcher(routingKey);
+ if (m.find())
+ {
+ for(LinkedBlockingQueue<MessageTransfer> queue : topicEx.get(key))
+ {
+ selected.add(queue);
+ }
+ }
+ }
+
+ return selected;
+ }
+
+ private void storeMessage(MessageTransfer msg,List<LinkedBlockingQueue<MessageTransfer>> selected)
+ {
+ for(LinkedBlockingQueue<MessageTransfer> queue : selected)
+ {
+ queue.offer(msg);
+ }
+ }
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/codec/AMQCodecFactory.java b/java/common/src/main/java/org/apache/qpid/codec/AMQCodecFactory.java
index c81af9760b..591dbd085b 100644
--- a/java/common/src/main/java/org/apache/qpid/codec/AMQCodecFactory.java
+++ b/java/common/src/main/java/org/apache/qpid/codec/AMQCodecFactory.java
@@ -20,6 +20,9 @@
*/
package org.apache.qpid.codec;
+import org.apache.mina.filter.codec.ProtocolCodecFactory;
+import org.apache.mina.filter.codec.ProtocolDecoder;
+import org.apache.mina.filter.codec.ProtocolEncoder;
import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
/**
@@ -28,11 +31,14 @@ import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
*
* <p/><table id="crc"><caption>CRC Card</caption>
* <tr><th> Responsibilities <th> Collaborations.
+ * <tr><td> Supply the protocol encoder. <td> {@link AMQEncoder}
* <tr><td> Supply the protocol decoder. <td> {@link AMQDecoder}
* </table>
*/
-public class AMQCodecFactory
+public class AMQCodecFactory implements ProtocolCodecFactory
{
+ /** Holds the protocol encoder. */
+ private final AMQEncoder _encoder = new AMQEncoder();
/** Holds the protocol decoder. */
private final AMQDecoder _frameDecoder;
@@ -50,6 +56,15 @@ public class AMQCodecFactory
_frameDecoder = new AMQDecoder(expectProtocolInitiation, session);
}
+ /**
+ * Gets the AMQP encoder.
+ *
+ * @return The AMQP encoder.
+ */
+ public ProtocolEncoder getEncoder()
+ {
+ return _encoder;
+ }
/**
* Gets the AMQP decoder.
diff --git a/java/common/src/main/java/org/apache/qpid/codec/AMQDecoder.java b/java/common/src/main/java/org/apache/qpid/codec/AMQDecoder.java
index 69bf73bb49..281c0761d9 100644
--- a/java/common/src/main/java/org/apache/qpid/codec/AMQDecoder.java
+++ b/java/common/src/main/java/org/apache/qpid/codec/AMQDecoder.java
@@ -20,9 +20,13 @@
*/
package org.apache.qpid.codec;
-import java.io.*;
-import java.nio.ByteBuffer;
-import java.util.*;
+import java.util.ArrayList;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.common.SimpleByteBufferAllocator;
+import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
+import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import org.apache.qpid.framing.AMQDataBlock;
import org.apache.qpid.framing.AMQDataBlockDecoder;
@@ -50,8 +54,11 @@ import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
* @todo If protocol initiation decoder not needed, then don't create it. Probably not a big deal, but it adds to the
* per-session overhead.
*/
-public class AMQDecoder
+public class AMQDecoder extends CumulativeProtocolDecoder
{
+
+ private static final String BUFFER = AMQDecoder.class.getName() + ".Buffer";
+
/** Holds the 'normal' AMQP data decoder. */
private AMQDataBlockDecoder _dataBlockDecoder = new AMQDataBlockDecoder();
@@ -60,11 +67,12 @@ public class AMQDecoder
/** Flag to indicate whether this decoder needs to handle protocol initiation. */
private boolean _expectProtocolInitiation;
+ private boolean firstDecode = true;
private AMQMethodBodyFactory _bodyFactory;
- private List<ByteArrayInputStream> _remainingBufs = new ArrayList<ByteArrayInputStream>();
-
+ private ByteBuffer _remainingBuf;
+
/**
* Creates a new AMQP decoder.
*
@@ -76,7 +84,98 @@ public class AMQDecoder
_bodyFactory = new AMQMethodBodyFactory(session);
}
+ /**
+ * Delegates decoding AMQP from the data buffer that Mina has retrieved from the wire, to the data or protocol
+ * intiation decoders.
+ *
+ * @param session The Mina session.
+ * @param in The raw byte buffer.
+ * @param out The Mina object output gatherer to write decoded objects to.
+ *
+ * @return <tt>true</tt> if the data was decoded, <tt>false<tt> if more is needed and the data should accumulate.
+ *
+ * @throws Exception If the data cannot be decoded for any reason.
+ */
+ protected boolean doDecode(IoSession session, ByteBuffer in, ProtocolDecoderOutput out) throws Exception
+ {
+
+ boolean decoded;
+ if (_expectProtocolInitiation
+ || (firstDecode
+ && (in.remaining() > 0)
+ && (in.get(in.position()) == (byte)'A')))
+ {
+ decoded = doDecodePI(session, in, out);
+ }
+ else
+ {
+ decoded = doDecodeDataBlock(session, in, out);
+ }
+ if(firstDecode && decoded)
+ {
+ firstDecode = false;
+ }
+ return decoded;
+ }
+
+ /**
+ * Decodes AMQP data, delegating the decoding to an {@link AMQDataBlockDecoder}.
+ *
+ * @param session The Mina session.
+ * @param in The raw byte buffer.
+ * @param out The Mina object output gatherer to write decoded objects to.
+ *
+ * @return <tt>true</tt> if the data was decoded, <tt>false<tt> if more is needed and the data should accumulate.
+ *
+ * @throws Exception If the data cannot be decoded for any reason.
+ */
+ protected boolean doDecodeDataBlock(IoSession session, ByteBuffer in, ProtocolDecoderOutput out) throws Exception
+ {
+ int pos = in.position();
+ boolean enoughData = _dataBlockDecoder.decodable(in.buf());
+ in.position(pos);
+ if (!enoughData)
+ {
+ // returning false means it will leave the contents in the buffer and
+ // call us again when more data has been read
+ return false;
+ }
+ else
+ {
+ _dataBlockDecoder.decode(session, in, out);
+
+ return true;
+ }
+ }
+
+ /**
+ * Decodes an AMQP initiation, delegating the decoding to a {@link ProtocolInitiation.Decoder}.
+ *
+ * @param session The Mina session.
+ * @param in The raw byte buffer.
+ * @param out The Mina object output gatherer to write decoded objects to.
+ *
+ * @return <tt>true</tt> if the data was decoded, <tt>false<tt> if more is needed and the data should accumulate.
+ *
+ * @throws Exception If the data cannot be decoded for any reason.
+ */
+ private boolean doDecodePI(IoSession session, ByteBuffer in, ProtocolDecoderOutput out) throws Exception
+ {
+ boolean enoughData = _piDecoder.decodable(in.buf());
+ if (!enoughData)
+ {
+ // returning false means it will leave the contents in the buffer and
+ // call us again when more data has been read
+ return false;
+ }
+ else
+ {
+ ProtocolInitiation pi = new ProtocolInitiation(in.buf());
+ out.write(pi);
+ return true;
+ }
+ }
/**
* Sets the protocol initation flag, that determines whether decoding is handled by the data decoder of the protocol
@@ -90,169 +189,152 @@ public class AMQDecoder
_expectProtocolInitiation = expectProtocolInitiation;
}
- private class RemainingByteArrayInputStream extends InputStream
- {
- private int _currentListPos;
- private int _markPos;
-
- @Override
- public int read() throws IOException
+ /**
+ * Cumulates content of <tt>in</tt> into internal buffer and forwards
+ * decoding request to {@link #doDecode(IoSession, ByteBuffer, ProtocolDecoderOutput)}.
+ * <tt>doDecode()</tt> is invoked repeatedly until it returns <tt>false</tt>
+ * and the cumulative buffer is compacted after decoding ends.
+ *
+ * @throws IllegalStateException if your <tt>doDecode()</tt> returned
+ * <tt>true</tt> not consuming the cumulative buffer.
+ */
+ public void decode( IoSession session, ByteBuffer in,
+ ProtocolDecoderOutput out ) throws Exception
+ {
+ ByteBuffer buf = ( ByteBuffer ) session.getAttribute( BUFFER );
+ // if we have a session buffer, append data to that otherwise
+ // use the buffer read from the network directly
+ if( buf != null )
{
- ByteArrayInputStream currentStream = _remainingBufs.get(_currentListPos);
- if(currentStream.available() > 0)
- {
- return currentStream.read();
- }
- else if((_currentListPos == _remainingBufs.size())
- || (++_currentListPos == _remainingBufs.size()))
- {
- return -1;
- }
- else
- {
-
- ByteArrayInputStream stream = _remainingBufs.get(_currentListPos);
- stream.mark(0);
- return stream.read();
- }
+ buf.put( in );
+ buf.flip();
}
-
- @Override
- public int read(final byte[] b, final int off, final int len) throws IOException
+ else
{
+ buf = in;
+ }
- if(_currentListPos == _remainingBufs.size())
- {
- return -1;
- }
- else
+ for( ;; )
+ {
+ int oldPos = buf.position();
+ boolean decoded = doDecode( session, buf, out );
+ if( decoded )
{
- ByteArrayInputStream currentStream = _remainingBufs.get(_currentListPos);
- final int available = currentStream.available();
- int read = currentStream.read(b, off, len > available ? available : len);
- if(read < len)
+ if( buf.position() == oldPos )
{
- if(_currentListPos++ != _remainingBufs.size())
- {
- _remainingBufs.get(_currentListPos).mark(0);
- }
- int correctRead = read == -1 ? 0 : read;
- int subRead = read(b, off+correctRead, len-correctRead);
- if(subRead == -1)
- {
- return read;
- }
- else
- {
- return correctRead+subRead;
- }
+ throw new IllegalStateException(
+ "doDecode() can't return true when buffer is not consumed." );
}
- else
+
+ if( !buf.hasRemaining() )
{
- return len;
+ break;
}
}
- }
-
- @Override
- public int available() throws IOException
- {
- int total = 0;
- for(int i = _currentListPos; i < _remainingBufs.size(); i++)
+ else
{
- total += _remainingBufs.get(i).available();
+ break;
}
- return total;
}
- @Override
- public void mark(final int readlimit)
+ // if there is any data left that cannot be decoded, we store
+ // it in a buffer in the session and next time this decoder is
+ // invoked the session buffer gets appended to
+ if ( buf.hasRemaining() )
{
- _markPos = _currentListPos;
- final ByteArrayInputStream stream = _remainingBufs.get(_currentListPos);
- if(stream != null)
- {
- stream.mark(readlimit);
- }
+ storeRemainingInSession( buf, session );
}
+ else
+ {
+ removeSessionBuffer( session );
+ }
+ }
+
+ /**
+ * Releases the cumulative buffer used by the specified <tt>session</tt>.
+ * Please don't forget to call <tt>super.dispose( session )</tt> when
+ * you override this method.
+ */
+ public void dispose( IoSession session ) throws Exception
+ {
+ removeSessionBuffer( session );
+ }
- @Override
- public void reset() throws IOException
+ private void removeSessionBuffer(IoSession session)
+ {
+ ByteBuffer buf = ( ByteBuffer ) session.getAttribute( BUFFER );
+ if( buf != null )
{
- _currentListPos = _markPos;
- final int size = _remainingBufs.size();
- if(_currentListPos < size)
- {
- _remainingBufs.get(_currentListPos).reset();
- }
- for(int i = _currentListPos+1; i<size; i++)
- {
- _remainingBufs.get(i).reset();
- }
+ buf.release();
+ session.removeAttribute( BUFFER );
}
}
+ private static final SimpleByteBufferAllocator SIMPLE_BYTE_BUFFER_ALLOCATOR = new SimpleByteBufferAllocator();
+
+ private void storeRemainingInSession(ByteBuffer buf, IoSession session)
+ {
+ ByteBuffer remainingBuf = SIMPLE_BYTE_BUFFER_ALLOCATOR.allocate( buf.remaining(), false );
+ remainingBuf.setAutoExpand( true );
+ remainingBuf.put( buf );
+ session.setAttribute( BUFFER, remainingBuf );
+ }
- public ArrayList<AMQDataBlock> decodeBuffer(ByteBuffer buf) throws AMQFrameDecodingException, AMQProtocolVersionException, IOException
+ public ArrayList<AMQDataBlock> decodeBuffer(java.nio.ByteBuffer buf) throws AMQFrameDecodingException, AMQProtocolVersionException
{
// get prior remaining data from accumulator
ArrayList<AMQDataBlock> dataBlocks = new ArrayList<AMQDataBlock>();
- DataInputStream msg;
-
-
- ByteArrayInputStream bais = new ByteArrayInputStream(buf.array(),buf.arrayOffset()+buf.position(), buf.remaining());
- if(!_remainingBufs.isEmpty())
+ ByteBuffer msg;
+ // if we have a session buffer, append data to that otherwise
+ // use the buffer read from the network directly
+ if( _remainingBuf != null )
{
- _remainingBufs.add(bais);
- msg = new DataInputStream(new RemainingByteArrayInputStream());
+ _remainingBuf.put(buf);
+ _remainingBuf.flip();
+ msg = _remainingBuf;
}
else
{
- msg = new DataInputStream(bais);
+ msg = ByteBuffer.wrap(buf);
}
-
- boolean enoughData = true;
- while (enoughData)
+
+ if (_expectProtocolInitiation
+ || (firstDecode
+ && (msg.remaining() > 0)
+ && (msg.get(msg.position()) == (byte)'A')))
{
- if(!_expectProtocolInitiation)
+ if (_piDecoder.decodable(msg.buf()))
{
- enoughData = _dataBlockDecoder.decodable(msg);
- if (enoughData)
- {
- dataBlocks.add(_dataBlockDecoder.createAndPopulateFrame(_bodyFactory, msg));
- }
+ dataBlocks.add(new ProtocolInitiation(msg.buf()));
}
- else
+ }
+ else
+ {
+ boolean enoughData = true;
+ while (enoughData)
{
- enoughData = _piDecoder.decodable(msg);
- if (enoughData)
- {
- dataBlocks.add(new ProtocolInitiation(msg));
- }
-
- }
+ int pos = msg.position();
- if(!enoughData)
- {
- if(!_remainingBufs.isEmpty())
+ enoughData = _dataBlockDecoder.decodable(msg);
+ msg.position(pos);
+ if (enoughData)
{
- _remainingBufs.remove(_remainingBufs.size()-1);
- ListIterator<ByteArrayInputStream> iterator = _remainingBufs.listIterator();
- while(iterator.hasNext() && iterator.next().available() == 0)
- {
- iterator.remove();
- }
+ dataBlocks.add(_dataBlockDecoder.createAndPopulateFrame(_bodyFactory, msg));
}
- if(bais.available()!=0)
+ else
{
- byte[] remaining = new byte[bais.available()];
- bais.read(remaining);
- _remainingBufs.add(new ByteArrayInputStream(remaining));
+ _remainingBuf = SIMPLE_BYTE_BUFFER_ALLOCATOR.allocate(msg.remaining(), false);
+ _remainingBuf.setAutoExpand(true);
+ _remainingBuf.put(msg);
}
}
}
+ if(firstDecode && dataBlocks.size() > 0)
+ {
+ firstDecode = false;
+ }
return dataBlocks;
}
}
diff --git a/java/common/src/main/java/org/apache/qpid/codec/AMQEncoder.java b/java/common/src/main/java/org/apache/qpid/codec/AMQEncoder.java
new file mode 100644
index 0000000000..53f48ae1c8
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/codec/AMQEncoder.java
@@ -0,0 +1,66 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.codec;
+
+import org.apache.mina.common.IoSession;
+import org.apache.mina.filter.codec.ProtocolEncoder;
+import org.apache.mina.filter.codec.ProtocolEncoderOutput;
+
+import org.apache.qpid.framing.AMQDataBlockEncoder;
+
+/**
+ * AMQEncoder delegates encoding of AMQP to a data encoder.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Delegate AMQP encoding. <td> {@link AMQDataBlockEncoder}
+ * </table>
+ *
+ * @todo This class just delegates to another, so seems to be pointless. Unless it is going to handle some
+ * responsibilities in the future, then drop it.
+ */
+public class AMQEncoder implements ProtocolEncoder
+{
+ /** The data encoder that is delegated to. */
+ private AMQDataBlockEncoder _dataBlockEncoder = new AMQDataBlockEncoder();
+
+ /**
+ * Encodes AMQP.
+ *
+ * @param session The Mina session.
+ * @param message The data object to encode.
+ * @param out The Mina writer to output the raw byte data to.
+ *
+ * @throws Exception If the data cannot be encoded for any reason.
+ */
+ public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception
+ {
+ _dataBlockEncoder.encode(session, message, out);
+ }
+
+ /**
+ * Does nothing. Called by Mina to allow this to clean up resources when it is no longer needed.
+ *
+ * @param session The Mina session.
+ */
+ public void dispose(IoSession session)
+ { }
+}
diff --git a/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java b/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java
index 62ded5b2d8..0dd21238a7 100644
--- a/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java
+++ b/java/common/src/main/java/org/apache/qpid/configuration/ClientProperties.java
@@ -23,7 +23,7 @@ package org.apache.qpid.configuration;
*/
public class ClientProperties
{
-
+
/**
* Currently with Qpid it is not possible to change the client ID.
* If one is not specified upon connection construction, an id is generated automatically.
@@ -68,50 +68,67 @@ public class ClientProperties
* by the broker in TuneOK it will be used as the heartbeat interval.
* If not a warning will be printed and the max value specified for
* heartbeat in TuneOK will be used
- *
+ *
* The default idle timeout is set to 120 secs
*/
public static final String IDLE_TIMEOUT_PROP_NAME = "idle_timeout";
public static final long DEFAULT_IDLE_TIMEOUT = 120000;
-
+
public static final String HEARTBEAT = "qpid.heartbeat";
public static final int HEARTBEAT_DEFAULT = 120;
-
+
/**
* This value will be used to determine the default destination syntax type.
* Currently the two types are Binding URL (java only) and the Addressing format (used by
- * all clients).
+ * all clients).
*/
public static final String DEST_SYNTAX = "qpid.dest_syntax";
-
+
public static final String USE_LEGACY_MAP_MESSAGE_FORMAT = "qpid.use_legacy_map_message";
- public static final String AMQP_VERSION = "qpid.amqp.version";
-
- public static final String QPID_VERIFY_CLIENT_ID = "qpid.verify_client_id";
+ /**
+ * ==========================================================
+ * Those properties are used when the io size should be bounded
+ * ==========================================================
+ */
/**
- * System properties to change the default timeout used during
- * synchronous operations.
+ * When set to true the io layer throttle down producers and consumers
+ * when written or read messages are accumulating and exceeding a certain size.
+ * This is especially useful when a the producer rate is greater than the network
+ * speed.
+ * type: boolean
*/
- public static final String QPID_SYNC_OP_TIMEOUT = "qpid.sync_op_timeout";
- public static final String AMQJ_DEFAULT_SYNCWRITE_TIMEOUT = "amqj.default_syncwrite_timeout";
+ public static final String PROTECTIO_PROP_NAME = "protectio";
+ //=== The following properties are only used when the previous one is true.
/**
- * A default timeout value for synchronous operations
+ * Max size of read messages that can be stored within the MINA layer
+ * type: int
*/
- public static final int DEFAULT_SYNC_OPERATION_TIMEOUT = 60000;
+ public static final String READ_BUFFER_LIMIT_PROP_NAME = "qpid.read.buffer.limit";
+ public static final String READ_BUFFER_LIMIT_DEFAULT = "262144";
+ /**
+ * Max size of written messages that can be stored within the MINA layer
+ * type: int
+ */
+ public static final String WRITE_BUFFER_LIMIT_PROP_NAME = "qpid.read.buffer.limit";
+ public static final String WRITE_BUFFER_LIMIT_DEFAULT = "262144";
+ public static final String AMQP_VERSION = "qpid.amqp.version";
+
+ private static ClientProperties _instance = new ClientProperties();
+
/*
- public static final QpidProperty<Boolean> IGNORE_SET_CLIENTID_PROP_NAME =
+ public static final QpidProperty<Boolean> IGNORE_SET_CLIENTID_PROP_NAME =
QpidProperty.booleanProperty(false,"qpid.ignore_set_client_id","ignore_setclientID");
-
+
public static final QpidProperty<Boolean> SYNC_PERSISTENT_PROP_NAME =
QpidProperty.booleanProperty(false,"qpid.sync_persistence","sync_persistence");
-
-
+
+
public static final QpidProperty<Integer> MAX_PREFETCH_PROP_NAME =
QpidProperty.intProperty(500,"qpid.max_prefetch","max_prefetch"); */
-
-
+
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQBody.java b/java/common/src/main/java/org/apache/qpid/framing/AMQBody.java
index ebdad12178..fe04155bb8 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/AMQBody.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/AMQBody.java
@@ -20,9 +20,7 @@
*/
package org.apache.qpid.framing;
-import java.io.DataOutputStream;
-import java.io.IOException;
-
+import org.apache.mina.common.ByteBuffer;
import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
import org.apache.qpid.AMQException;
@@ -36,7 +34,7 @@ public interface AMQBody
*/
public abstract int getSize();
- public void writePayload(DataOutputStream buffer) throws IOException;
+ public void writePayload(ByteBuffer buffer);
- void handle(final int channelId, final AMQVersionAwareProtocolSession amqProtocolSession) throws AMQException;
+ void handle(final int channelId, final AMQVersionAwareProtocolSession amqMinaProtocolSession) throws AMQException;
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlock.java b/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlock.java
index 00c1f5aae5..a2fc3a03ef 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlock.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlock.java
@@ -20,10 +20,7 @@
*/
package org.apache.qpid.framing;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-
+import org.apache.mina.common.ByteBuffer;
/**
* A data block represents something that has a size in bytes and the ability to write itself to a byte
@@ -42,6 +39,25 @@ public abstract class AMQDataBlock implements EncodableAMQDataBlock
* Writes the datablock to the specified buffer.
* @param buffer
*/
- public abstract void writePayload(DataOutputStream buffer) throws IOException;
+ public abstract void writePayload(ByteBuffer buffer);
+
+ public ByteBuffer toByteBuffer()
+ {
+ final ByteBuffer buffer = ByteBuffer.allocate((int)getSize());
+
+ writePayload(buffer);
+ buffer.flip();
+ return buffer;
+ }
+
+ public java.nio.ByteBuffer toNioByteBuffer()
+ {
+ final java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate((int) getSize());
+
+ ByteBuffer buf = ByteBuffer.wrap(buffer);
+ writePayload(buf);
+ buffer.flip();
+ return buffer;
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java b/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java
index 2165cadd14..228867b2b0 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java
@@ -20,14 +20,18 @@
*/
package org.apache.qpid.framing;
+import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.filter.codec.ProtocolDecoderOutput;
+
+import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.DataInputStream;
-import java.io.IOException;
-
public class AMQDataBlockDecoder
{
+ private static final String SESSION_METHOD_BODY_FACTORY = "QPID_SESSION_METHOD_BODY_FACTORY";
private static final BodyFactory[] _bodiesSupported = new BodyFactory[Byte.MAX_VALUE];
@@ -43,32 +47,27 @@ public class AMQDataBlockDecoder
public AMQDataBlockDecoder()
{ }
- public boolean decodable(DataInputStream in) throws AMQFrameDecodingException, IOException
+ public boolean decodable(java.nio.ByteBuffer in) throws AMQFrameDecodingException
{
- final int remainingAfterAttributes = in.available() - (1 + 2 + 4 + 1);
+ final int remainingAfterAttributes = in.remaining() - (1 + 2 + 4 + 1);
// type, channel, body length and end byte
if (remainingAfterAttributes < 0)
{
return false;
}
- in.mark(8);
- in.skip(1 + 2);
-
-
+ in.position(in.position() + 1 + 2);
// Get an unsigned int, lifted from MINA ByteBuffer getUnsignedInt()
- final long bodySize = in.readInt() & 0xffffffffL;
-
- in.reset();
+ final long bodySize = in.getInt() & 0xffffffffL;
return (remainingAfterAttributes >= bodySize);
}
- public AMQFrame createAndPopulateFrame(AMQMethodBodyFactory methodBodyFactory, DataInputStream in)
- throws AMQFrameDecodingException, AMQProtocolVersionException, IOException
+ public AMQFrame createAndPopulateFrame(AMQMethodBodyFactory methodBodyFactory, ByteBuffer in)
+ throws AMQFrameDecodingException, AMQProtocolVersionException
{
- final byte type = in.readByte();
+ final byte type = in.get();
BodyFactory bodyFactory;
if (type == AMQMethodBody.TYPE)
@@ -85,8 +84,8 @@ public class AMQDataBlockDecoder
throw new AMQFrameDecodingException(null, "Unsupported frame type: " + type, null);
}
- final int channel = in.readUnsignedShort();
- final long bodySize = EncodingUtils.readUnsignedInteger(in);
+ final int channel = in.getUnsignedShort();
+ final long bodySize = in.getUnsignedInt();
// bodySize can be zero
if ((channel < 0) || (bodySize < 0))
@@ -97,7 +96,7 @@ public class AMQDataBlockDecoder
AMQFrame frame = new AMQFrame(in, channel, bodySize, bodyFactory);
- byte marker = in.readByte();
+ byte marker = in.get();
if ((marker & 0xFF) != 0xCE)
{
throw new AMQFrameDecodingException(null, "End of frame marker not found. Read " + marker + " length=" + bodySize
@@ -107,4 +106,26 @@ public class AMQDataBlockDecoder
return frame;
}
+ public void decode(IoSession session, ByteBuffer in, ProtocolDecoderOutput out) throws Exception
+ {
+ AMQMethodBodyFactory bodyFactory = (AMQMethodBodyFactory) session.getAttribute(SESSION_METHOD_BODY_FACTORY);
+ if (bodyFactory == null)
+ {
+ AMQVersionAwareProtocolSession protocolSession = (AMQVersionAwareProtocolSession) session.getAttachment();
+ bodyFactory = new AMQMethodBodyFactory(protocolSession);
+ session.setAttribute(SESSION_METHOD_BODY_FACTORY, bodyFactory);
+ }
+
+ out.write(createAndPopulateFrame(bodyFactory, in));
+ }
+
+ public boolean decodable(ByteBuffer msg) throws AMQFrameDecodingException
+ {
+ return decodable(msg.buf());
+ }
+
+ public AMQDataBlock createAndPopulateFrame(AMQMethodBodyFactory factory, java.nio.ByteBuffer msg) throws AMQProtocolVersionException, AMQFrameDecodingException
+ {
+ return createAndPopulateFrame(factory, ByteBuffer.wrap(msg));
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockEncoder.java b/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockEncoder.java
new file mode 100644
index 0000000000..374644b4f2
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockEncoder.java
@@ -0,0 +1,61 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.framing;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.filter.codec.ProtocolEncoderOutput;
+import org.apache.mina.filter.codec.demux.MessageEncoder;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Collections;
+import java.util.Set;
+
+public final class AMQDataBlockEncoder implements MessageEncoder
+{
+ private static final Logger _logger = LoggerFactory.getLogger(AMQDataBlockEncoder.class);
+
+ private final Set _messageTypes = Collections.singleton(EncodableAMQDataBlock.class);
+
+ public AMQDataBlockEncoder()
+ { }
+
+ public void encode(IoSession session, Object message, ProtocolEncoderOutput out) throws Exception
+ {
+ final AMQDataBlock frame = (AMQDataBlock) message;
+
+ final ByteBuffer buffer = frame.toByteBuffer();
+
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Encoded frame byte-buffer is '" + EncodingUtils.convertToHexString(buffer) + "'");
+ }
+
+ out.write(buffer);
+ }
+
+ public Set getMessageTypes()
+ {
+ return _messageTypes;
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQFrame.java b/java/common/src/main/java/org/apache/qpid/framing/AMQFrame.java
index 6acf60a5b3..02a46f3748 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/AMQFrame.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/AMQFrame.java
@@ -20,9 +20,7 @@
*/
package org.apache.qpid.framing;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
+import org.apache.mina.common.ByteBuffer;
public class AMQFrame extends AMQDataBlock implements EncodableAMQDataBlock
{
@@ -38,7 +36,7 @@ public class AMQFrame extends AMQDataBlock implements EncodableAMQDataBlock
_bodyFrame = bodyFrame;
}
- public AMQFrame(final DataInputStream in, final int channel, final long bodySize, final BodyFactory bodyFactory) throws AMQFrameDecodingException, IOException
+ public AMQFrame(final ByteBuffer in, final int channel, final long bodySize, final BodyFactory bodyFactory) throws AMQFrameDecodingException
{
this._channel = channel;
this._bodyFrame = bodyFactory.createBody(in,bodySize);
@@ -55,13 +53,13 @@ public class AMQFrame extends AMQDataBlock implements EncodableAMQDataBlock
}
- public void writePayload(DataOutputStream buffer) throws IOException
+ public void writePayload(ByteBuffer buffer)
{
- buffer.writeByte(_bodyFrame.getFrameType());
+ buffer.put(_bodyFrame.getFrameType());
EncodingUtils.writeUnsignedShort(buffer, _channel);
EncodingUtils.writeUnsignedInteger(buffer, _bodyFrame.getSize());
_bodyFrame.writePayload(buffer);
- buffer.writeByte(FRAME_END_BYTE);
+ buffer.put(FRAME_END_BYTE);
}
public final int getChannel()
@@ -79,48 +77,48 @@ public class AMQFrame extends AMQDataBlock implements EncodableAMQDataBlock
return "Frame channelId: " + _channel + ", bodyFrame: " + String.valueOf(_bodyFrame);
}
- public static void writeFrame(DataOutputStream buffer, final int channel, AMQBody body) throws IOException
+ public static void writeFrame(ByteBuffer buffer, final int channel, AMQBody body)
{
- buffer.writeByte(body.getFrameType());
+ buffer.put(body.getFrameType());
EncodingUtils.writeUnsignedShort(buffer, channel);
EncodingUtils.writeUnsignedInteger(buffer, body.getSize());
body.writePayload(buffer);
- buffer.writeByte(FRAME_END_BYTE);
+ buffer.put(FRAME_END_BYTE);
}
- public static void writeFrames(DataOutputStream buffer, final int channel, AMQBody body1, AMQBody body2) throws IOException
+ public static void writeFrames(ByteBuffer buffer, final int channel, AMQBody body1, AMQBody body2)
{
- buffer.writeByte(body1.getFrameType());
+ buffer.put(body1.getFrameType());
EncodingUtils.writeUnsignedShort(buffer, channel);
EncodingUtils.writeUnsignedInteger(buffer, body1.getSize());
body1.writePayload(buffer);
- buffer.writeByte(FRAME_END_BYTE);
- buffer.writeByte(body2.getFrameType());
+ buffer.put(FRAME_END_BYTE);
+ buffer.put(body2.getFrameType());
EncodingUtils.writeUnsignedShort(buffer, channel);
EncodingUtils.writeUnsignedInteger(buffer, body2.getSize());
body2.writePayload(buffer);
- buffer.writeByte(FRAME_END_BYTE);
+ buffer.put(FRAME_END_BYTE);
}
- public static void writeFrames(DataOutputStream buffer, final int channel, AMQBody body1, AMQBody body2, AMQBody body3) throws IOException
+ public static void writeFrames(ByteBuffer buffer, final int channel, AMQBody body1, AMQBody body2, AMQBody body3)
{
- buffer.writeByte(body1.getFrameType());
+ buffer.put(body1.getFrameType());
EncodingUtils.writeUnsignedShort(buffer, channel);
EncodingUtils.writeUnsignedInteger(buffer, body1.getSize());
body1.writePayload(buffer);
- buffer.writeByte(FRAME_END_BYTE);
- buffer.writeByte(body2.getFrameType());
+ buffer.put(FRAME_END_BYTE);
+ buffer.put(body2.getFrameType());
EncodingUtils.writeUnsignedShort(buffer, channel);
EncodingUtils.writeUnsignedInteger(buffer, body2.getSize());
body2.writePayload(buffer);
- buffer.writeByte(FRAME_END_BYTE);
- buffer.writeByte(body3.getFrameType());
+ buffer.put(FRAME_END_BYTE);
+ buffer.put(body3.getFrameType());
EncodingUtils.writeUnsignedShort(buffer, channel);
EncodingUtils.writeUnsignedInteger(buffer, body3.getSize());
body3.writePayload(buffer);
- buffer.writeByte(FRAME_END_BYTE);
+ buffer.put(FRAME_END_BYTE);
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBody.java b/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBody.java
index a076d0e5a1..4763b22290 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBody.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBody.java
@@ -20,14 +20,12 @@
*/
package org.apache.qpid.framing;
+import org.apache.mina.common.ByteBuffer;
import org.apache.qpid.AMQChannelException;
import org.apache.qpid.AMQConnectionException;
import org.apache.qpid.AMQException;
import org.apache.qpid.protocol.AMQConstant;
-import java.io.DataOutputStream;
-import java.io.IOException;
-
public interface AMQMethodBody extends AMQBody
{
public static final byte TYPE = 1;
@@ -45,12 +43,12 @@ public interface AMQMethodBody extends AMQBody
/** @return unsigned short */
public int getMethod();
- public void writeMethodPayload(DataOutputStream buffer) throws IOException;
+ public void writeMethodPayload(ByteBuffer buffer);
public int getSize();
- public void writePayload(DataOutputStream buffer) throws IOException;
+ public void writePayload(ByteBuffer buffer);
//public abstract void populateMethodBodyFromBuffer(ByteBuffer buffer) throws AMQFrameDecodingException;
diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyFactory.java b/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyFactory.java
index 7fceb082ee..1a7022c11b 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyFactory.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyFactory.java
@@ -20,14 +20,13 @@
*/
package org.apache.qpid.framing;
+import org.apache.mina.common.ByteBuffer;
+
import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.DataInputStream;
-import java.io.IOException;
-
public class AMQMethodBodyFactory implements BodyFactory
{
private static final Logger _log = LoggerFactory.getLogger(AMQMethodBodyFactory.class);
@@ -39,7 +38,7 @@ public class AMQMethodBodyFactory implements BodyFactory
_protocolSession = protocolSession;
}
- public AMQBody createBody(DataInputStream in, long bodySize) throws AMQFrameDecodingException, IOException
+ public AMQBody createBody(ByteBuffer in, long bodySize) throws AMQFrameDecodingException
{
return _protocolSession.getMethodRegistry().convertToBody(in, bodySize);
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyImpl.java b/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyImpl.java
index c73c1df701..cd3d721065 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyImpl.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyImpl.java
@@ -21,16 +21,13 @@ package org.apache.qpid.framing;
*
*/
+import org.apache.mina.common.ByteBuffer;
import org.apache.qpid.AMQChannelException;
import org.apache.qpid.AMQConnectionException;
import org.apache.qpid.AMQException;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-
public abstract class AMQMethodBodyImpl implements AMQMethodBody
{
public static final byte TYPE = 1;
@@ -101,7 +98,7 @@ public abstract class AMQMethodBodyImpl implements AMQMethodBody
return 2 + 2 + getBodySize();
}
- public void writePayload(DataOutputStream buffer) throws IOException
+ public void writePayload(ByteBuffer buffer)
{
EncodingUtils.writeUnsignedShort(buffer, getClazz());
EncodingUtils.writeUnsignedShort(buffer, getMethod());
@@ -109,12 +106,12 @@ public abstract class AMQMethodBodyImpl implements AMQMethodBody
}
- protected byte readByte(DataInputStream buffer) throws IOException
+ protected byte readByte(ByteBuffer buffer)
{
- return buffer.readByte();
+ return buffer.get();
}
- protected AMQShortString readAMQShortString(DataInputStream buffer) throws IOException
+ protected AMQShortString readAMQShortString(ByteBuffer buffer)
{
return EncodingUtils.readAMQShortString(buffer);
}
@@ -124,27 +121,27 @@ public abstract class AMQMethodBodyImpl implements AMQMethodBody
return EncodingUtils.encodedShortStringLength(string);
}
- protected void writeByte(DataOutputStream buffer, byte b) throws IOException
+ protected void writeByte(ByteBuffer buffer, byte b)
{
- buffer.writeByte(b);
+ buffer.put(b);
}
- protected void writeAMQShortString(DataOutputStream buffer, AMQShortString string) throws IOException
+ protected void writeAMQShortString(ByteBuffer buffer, AMQShortString string)
{
EncodingUtils.writeShortStringBytes(buffer, string);
}
- protected int readInt(DataInputStream buffer) throws IOException
+ protected int readInt(ByteBuffer buffer)
{
- return buffer.readInt();
+ return buffer.getInt();
}
- protected void writeInt(DataOutputStream buffer, int i) throws IOException
+ protected void writeInt(ByteBuffer buffer, int i)
{
- buffer.writeInt(i);
+ buffer.putInt(i);
}
- protected FieldTable readFieldTable(DataInputStream buffer) throws AMQFrameDecodingException, IOException
+ protected FieldTable readFieldTable(ByteBuffer buffer) throws AMQFrameDecodingException
{
return EncodingUtils.readFieldTable(buffer);
}
@@ -154,19 +151,19 @@ public abstract class AMQMethodBodyImpl implements AMQMethodBody
return EncodingUtils.encodedFieldTableLength(table); //To change body of created methods use File | Settings | File Templates.
}
- protected void writeFieldTable(DataOutputStream buffer, FieldTable table) throws IOException
+ protected void writeFieldTable(ByteBuffer buffer, FieldTable table)
{
EncodingUtils.writeFieldTableBytes(buffer, table);
}
- protected long readLong(DataInputStream buffer) throws IOException
+ protected long readLong(ByteBuffer buffer)
{
- return buffer.readLong();
+ return buffer.getLong();
}
- protected void writeLong(DataOutputStream buffer, long l) throws IOException
+ protected void writeLong(ByteBuffer buffer, long l)
{
- buffer.writeLong(l);
+ buffer.putLong(l);
}
protected int getSizeOf(byte[] response)
@@ -174,86 +171,87 @@ public abstract class AMQMethodBodyImpl implements AMQMethodBody
return (response == null) ? 4 : response.length + 4;
}
- protected void writeBytes(DataOutputStream buffer, byte[] data) throws IOException
+ protected void writeBytes(ByteBuffer buffer, byte[] data)
{
EncodingUtils.writeBytes(buffer,data);
}
- protected byte[] readBytes(DataInputStream buffer) throws IOException
+ protected byte[] readBytes(ByteBuffer buffer)
{
return EncodingUtils.readBytes(buffer);
}
- protected short readShort(DataInputStream buffer) throws IOException
+ protected short readShort(ByteBuffer buffer)
{
return EncodingUtils.readShort(buffer);
}
- protected void writeShort(DataOutputStream buffer, short s) throws IOException
+ protected void writeShort(ByteBuffer buffer, short s)
{
EncodingUtils.writeShort(buffer, s);
}
- protected Content readContent(DataInputStream buffer)
+ protected Content readContent(ByteBuffer buffer)
{
- return null;
+ return null; //To change body of created methods use File | Settings | File Templates.
}
protected int getSizeOf(Content body)
{
- return 0;
+ return 0; //To change body of created methods use File | Settings | File Templates.
}
- protected void writeContent(DataOutputStream buffer, Content body)
+ protected void writeContent(ByteBuffer buffer, Content body)
{
+ //To change body of created methods use File | Settings | File Templates.
}
- protected byte readBitfield(DataInputStream buffer) throws IOException
+ protected byte readBitfield(ByteBuffer buffer)
{
- return readByte(buffer);
+ return readByte(buffer); //To change body of created methods use File | Settings | File Templates.
}
- protected int readUnsignedShort(DataInputStream buffer) throws IOException
+ protected int readUnsignedShort(ByteBuffer buffer)
{
- return buffer.readUnsignedShort();
+ return buffer.getUnsignedShort(); //To change body of created methods use File | Settings | File Templates.
}
- protected void writeBitfield(DataOutputStream buffer, byte bitfield0) throws IOException
+ protected void writeBitfield(ByteBuffer buffer, byte bitfield0)
{
- buffer.writeByte(bitfield0);
+ buffer.put(bitfield0);
}
- protected void writeUnsignedShort(DataOutputStream buffer, int s) throws IOException
+ protected void writeUnsignedShort(ByteBuffer buffer, int s)
{
EncodingUtils.writeUnsignedShort(buffer, s);
}
- protected long readUnsignedInteger(DataInputStream buffer) throws IOException
+ protected long readUnsignedInteger(ByteBuffer buffer)
{
- return EncodingUtils.readUnsignedInteger(buffer);
+ return buffer.getUnsignedInt();
}
- protected void writeUnsignedInteger(DataOutputStream buffer, long i) throws IOException
+ protected void writeUnsignedInteger(ByteBuffer buffer, long i)
{
EncodingUtils.writeUnsignedInteger(buffer, i);
}
- protected short readUnsignedByte(DataInputStream buffer) throws IOException
+ protected short readUnsignedByte(ByteBuffer buffer)
{
- return (short) buffer.readUnsignedByte();
+ return buffer.getUnsigned();
}
- protected void writeUnsignedByte(DataOutputStream buffer, short unsignedByte) throws IOException
+ protected void writeUnsignedByte(ByteBuffer buffer, short unsignedByte)
{
EncodingUtils.writeUnsignedByte(buffer, unsignedByte);
}
- protected long readTimestamp(DataInputStream buffer) throws IOException
+ protected long readTimestamp(ByteBuffer buffer)
{
return EncodingUtils.readTimestamp(buffer);
}
- protected void writeTimestamp(DataOutputStream buffer, long t) throws IOException
+ protected void writeTimestamp(ByteBuffer buffer, long t)
{
EncodingUtils.writeTimestamp(buffer, t);
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyInstanceFactory.java b/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyInstanceFactory.java
index df4d8bdcb6..0c61d9db3c 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyInstanceFactory.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyInstanceFactory.java
@@ -21,11 +21,10 @@
package org.apache.qpid.framing;
-import java.io.DataInputStream;
-import java.io.IOException;
+import org.apache.mina.common.ByteBuffer;
public abstract interface AMQMethodBodyInstanceFactory
{
- public AMQMethodBody newInstance(DataInputStream buffer, long size) throws AMQFrameDecodingException, IOException;
+ public AMQMethodBody newInstance(ByteBuffer buffer, long size) throws AMQFrameDecodingException;
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQMethodFactory.java b/java/common/src/main/java/org/apache/qpid/framing/AMQMethodFactory.java
new file mode 100644
index 0000000000..bfcc38ad60
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/framing/AMQMethodFactory.java
@@ -0,0 +1,90 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.framing;
+
+import org.apache.mina.common.ByteBuffer;
+
+
+public interface AMQMethodFactory
+{
+
+ // Connection Methods
+
+ ConnectionCloseBody createConnectionClose();
+
+ // Access Methods
+
+ AccessRequestBody createAccessRequest(boolean active, boolean exclusive, boolean passive, boolean read, AMQShortString realm, boolean write);
+
+
+ // Tx Methods
+
+ TxSelectBody createTxSelect();
+
+ TxCommitBody createTxCommit();
+
+ TxRollbackBody createTxRollback();
+
+ // Channel Methods
+
+ ChannelOpenBody createChannelOpen();
+
+ ChannelCloseBody createChannelClose(int replyCode, AMQShortString replyText);
+
+ ChannelFlowBody createChannelFlow(boolean active);
+
+
+ // Exchange Methods
+
+
+ ExchangeBoundBody createExchangeBound(AMQShortString exchangeName,
+ AMQShortString queueName,
+ AMQShortString routingKey);
+
+ ExchangeDeclareBody createExchangeDeclare(AMQShortString name, AMQShortString type, int ticket);
+
+
+ // Queue Methods
+
+ QueueDeclareBody createQueueDeclare(AMQShortString name, FieldTable arguments, boolean autoDelete, boolean durable, boolean exclusive, boolean passive, int ticket);
+
+ QueueBindBody createQueueBind(AMQShortString queueName, AMQShortString exchangeName, AMQShortString routingKey, FieldTable arguments, int ticket);
+
+ QueueDeleteBody createQueueDelete(AMQShortString queueName, boolean ifEmpty, boolean ifUnused, int ticket);
+
+
+ // Message Methods
+
+ // In different versions of the protocol we change the class used for message transfer
+ // abstract this out so the appropriate methods are created
+ AMQMethodBody createRecover(boolean requeue);
+
+ AMQMethodBody createConsumer(AMQShortString tag, AMQShortString queueName, FieldTable arguments, boolean noAck, boolean exclusive, boolean noLocal, int ticket);
+
+ AMQMethodBody createConsumerCancel(AMQShortString consumerTag);
+
+ AMQMethodBody createAcknowledge(long deliveryTag, boolean multiple);
+
+ AMQMethodBody createRejectBody(long deliveryTag, boolean requeue);
+
+ AMQMethodBody createMessageQos(int prefetchCount, int prefetchSize);
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java b/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java
index cc9a33f4cf..39a9beb9e8 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/AMQShortString.java
@@ -21,12 +21,11 @@
package org.apache.qpid.framing;
+import org.apache.mina.common.ByteBuffer;
+
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
import java.util.*;
import java.lang.ref.WeakReference;
@@ -38,10 +37,6 @@ import java.lang.ref.WeakReference;
*/
public final class AMQShortString implements CharSequence, Comparable<AMQShortString>
{
- /**
- * The maximum number of octets in AMQ short string as defined in AMQP specification
- */
- public static final int MAX_LENGTH = 255;
private static final byte MINUS = (byte)'-';
private static final byte ZERO = (byte) '0';
@@ -123,19 +118,22 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt
public AMQShortString(byte[] data)
{
- if (data == null)
- {
- throw new NullPointerException("Cannot create AMQShortString with null data[]");
- }
- if (data.length > MAX_LENGTH)
- {
- throw new IllegalArgumentException("Cannot create AMQShortString with number of octets over 255!");
- }
+
_data = data.clone();
_length = data.length;
_offset = 0;
}
+ public AMQShortString(byte[] data, int pos)
+ {
+ final int size = data[pos++];
+ final byte[] dataCopy = new byte[size];
+ System.arraycopy(data,pos,dataCopy,0,size);
+ _length = size;
+ _data = dataCopy;
+ _offset = 0;
+ }
+
public AMQShortString(String data)
{
this((data == null) ? EMPTY_CHAR_ARRAY : data.toCharArray());
@@ -148,12 +146,7 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt
{
throw new NullPointerException("Cannot create AMQShortString with null char[]");
}
- // the current implementation of 0.8/0.9.x short string encoding
- // supports only ASCII characters
- if (data.length> MAX_LENGTH)
- {
- throw new IllegalArgumentException("Cannot create AMQShortString with number of octets over 255!");
- }
+
final int length = data.length;
final byte[] stringBytes = new byte[length];
int hash = 0;
@@ -172,17 +165,6 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt
public AMQShortString(CharSequence charSequence)
{
- if (charSequence == null)
- {
- // it should be possible to create short string for null data
- charSequence = "";
- }
- // the current implementation of 0.8/0.9.x short string encoding
- // supports only ASCII characters
- if (charSequence.length() > MAX_LENGTH)
- {
- throw new IllegalArgumentException("Cannot create AMQShortString with number of octets over 255!");
- }
final int length = charSequence.length();
final byte[] stringBytes = new byte[length];
int hash = 0;
@@ -200,33 +182,31 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt
}
- private AMQShortString(DataInputStream data, final int length) throws IOException
+ private AMQShortString(ByteBuffer data, final int length)
{
- if (length > MAX_LENGTH)
+ if(data.isDirect() || data.isReadOnly())
{
- throw new IllegalArgumentException("Cannot create AMQShortString with number of octets over 255!");
+ byte[] dataBytes = new byte[length];
+ data.get(dataBytes);
+ _data = dataBytes;
+ _offset = 0;
+ }
+ else
+ {
+
+ _data = data.array();
+ _offset = data.arrayOffset() + data.position();
+ data.skip(length);
+
}
- byte[] dataBytes = new byte[length];
- data.read(dataBytes);
- _data = dataBytes;
- _offset = 0;
_length = length;
}
private AMQShortString(final byte[] data, final int from, final int to)
{
- if (data == null)
- {
- throw new NullPointerException("Cannot create AMQShortString with null data[]");
- }
- int length = to - from;
- if (length > MAX_LENGTH)
- {
- throw new IllegalArgumentException("Cannot create AMQShortString with number of octets over 255!");
- }
_offset = from;
- _length = length;
+ _length = to - from;
_data = data;
}
@@ -265,9 +245,32 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt
return new CharSubSequence(start, end);
}
- public static AMQShortString readFromBuffer(DataInputStream buffer) throws IOException
+ public int writeToByteArray(byte[] encoding, int pos)
+ {
+ final int size = length();
+ encoding[pos++] = (byte) size;
+ System.arraycopy(_data,_offset,encoding,pos,size);
+ return pos+size;
+ }
+
+ public static AMQShortString readFromByteArray(byte[] byteEncodedDestination, int pos)
+ {
+
+
+ final AMQShortString shortString = new AMQShortString(byteEncodedDestination, pos);
+ if(shortString.length() == 0)
+ {
+ return null;
+ }
+ else
+ {
+ return shortString;
+ }
+ }
+
+ public static AMQShortString readFromBuffer(ByteBuffer buffer)
{
- final int length = buffer.readUnsignedByte();
+ final short length = buffer.getUnsigned();
if (length == 0)
{
return null;
@@ -293,13 +296,13 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt
}
}
- public void writeToBuffer(DataOutputStream buffer) throws IOException
+ public void writeToBuffer(ByteBuffer buffer)
{
final int size = length();
//buffer.setAutoExpand(true);
- buffer.write((byte) size);
- buffer.write(_data, _offset, size);
+ buffer.put((byte) size);
+ buffer.put(_data, _offset, size);
}
@@ -687,10 +690,6 @@ public final class AMQShortString implements CharSequence, Comparable<AMQShortSt
size += term.length();
}
- if (size > MAX_LENGTH)
- {
- throw new IllegalArgumentException("Cannot create AMQShortString with number of octets over 255!");
- }
byte[] data = new byte[size];
int pos = 0;
final byte[] delimData = delim._data;
diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQType.java b/java/common/src/main/java/org/apache/qpid/framing/AMQType.java
index f3da64e639..14fb63da03 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/AMQType.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/AMQType.java
@@ -20,9 +20,8 @@
*/
package org.apache.qpid.framing;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
+import org.apache.mina.common.ByteBuffer;
+
import java.math.BigDecimal;
/**
@@ -61,12 +60,12 @@ public enum AMQType
}
}
- public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+ public void writeValueImpl(Object value, ByteBuffer buffer)
{
EncodingUtils.writeLongStringBytes(buffer, (String) value);
}
- public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+ public Object readValueFromBuffer(ByteBuffer buffer)
{
return EncodingUtils.readLongString(buffer);
}
@@ -107,12 +106,12 @@ public enum AMQType
}
}
- public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+ public void writeValueImpl(Object value, ByteBuffer buffer)
{
EncodingUtils.writeUnsignedInteger(buffer, (Long) value);
}
- public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+ public Object readValueFromBuffer(ByteBuffer buffer)
{
return EncodingUtils.readUnsignedInteger(buffer);
}
@@ -138,7 +137,7 @@ public enum AMQType
}
}
- public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+ public void writeValueImpl(Object value, ByteBuffer buffer)
{
BigDecimal bd = (BigDecimal) value;
@@ -151,7 +150,7 @@ public enum AMQType
EncodingUtils.writeInteger(buffer, unscaled);
}
- public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+ public Object readValueFromBuffer(ByteBuffer buffer)
{
byte places = EncodingUtils.readByte(buffer);
@@ -183,12 +182,12 @@ public enum AMQType
}
}
- public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+ public void writeValueImpl(Object value, ByteBuffer buffer)
{
EncodingUtils.writeLong(buffer, (Long) value);
}
- public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+ public Object readValueFromBuffer(ByteBuffer buffer)
{
return EncodingUtils.readLong(buffer);
}
@@ -247,7 +246,7 @@ public enum AMQType
* @param value An instance of the type.
* @param buffer The byte buffer to write it to.
*/
- public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+ public void writeValueImpl(Object value, ByteBuffer buffer)
{
// Ensure that the value is a FieldTable.
if (!(value instanceof FieldTable))
@@ -268,7 +267,7 @@ public enum AMQType
*
* @return An instance of the type.
*/
- public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+ public Object readValueFromBuffer(ByteBuffer buffer)
{
try
{
@@ -302,10 +301,10 @@ public enum AMQType
}
}
- public void writeValueImpl(Object value, DataOutputStream buffer)
+ public void writeValueImpl(Object value, ByteBuffer buffer)
{ }
- public Object readValueFromBuffer(DataInputStream buffer)
+ public Object readValueFromBuffer(ByteBuffer buffer)
{
return null;
}
@@ -331,12 +330,12 @@ public enum AMQType
}
}
- public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+ public void writeValueImpl(Object value, ByteBuffer buffer)
{
EncodingUtils.writeLongstr(buffer, (byte[]) value);
}
- public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+ public Object readValueFromBuffer(ByteBuffer buffer)
{
return EncodingUtils.readLongstr(buffer);
}
@@ -361,12 +360,12 @@ public enum AMQType
}
}
- public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+ public void writeValueImpl(Object value, ByteBuffer buffer)
{
EncodingUtils.writeLongStringBytes(buffer, (String) value);
}
- public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+ public Object readValueFromBuffer(ByteBuffer buffer)
{
return EncodingUtils.readLongString(buffer);
}
@@ -392,12 +391,12 @@ public enum AMQType
}
}
- public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+ public void writeValueImpl(Object value, ByteBuffer buffer)
{
EncodingUtils.writeLongStringBytes(buffer, (String) value);
}
- public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+ public Object readValueFromBuffer(ByteBuffer buffer)
{
return EncodingUtils.readLongString(buffer);
}
@@ -427,12 +426,12 @@ public enum AMQType
}
}
- public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+ public void writeValueImpl(Object value, ByteBuffer buffer)
{
EncodingUtils.writeBoolean(buffer, (Boolean) value);
}
- public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+ public Object readValueFromBuffer(ByteBuffer buffer)
{
return EncodingUtils.readBoolean(buffer);
}
@@ -462,12 +461,12 @@ public enum AMQType
}
}
- public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+ public void writeValueImpl(Object value, ByteBuffer buffer)
{
EncodingUtils.writeChar(buffer, (Character) value);
}
- public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+ public Object readValueFromBuffer(ByteBuffer buffer)
{
return EncodingUtils.readChar(buffer);
}
@@ -497,12 +496,12 @@ public enum AMQType
}
}
- public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+ public void writeValueImpl(Object value, ByteBuffer buffer)
{
EncodingUtils.writeByte(buffer, (Byte) value);
}
- public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+ public Object readValueFromBuffer(ByteBuffer buffer)
{
return EncodingUtils.readByte(buffer);
}
@@ -536,12 +535,12 @@ public enum AMQType
}
}
- public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+ public void writeValueImpl(Object value, ByteBuffer buffer)
{
EncodingUtils.writeShort(buffer, (Short) value);
}
- public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+ public Object readValueFromBuffer(ByteBuffer buffer)
{
return EncodingUtils.readShort(buffer);
}
@@ -578,12 +577,12 @@ public enum AMQType
}
}
- public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+ public void writeValueImpl(Object value, ByteBuffer buffer)
{
EncodingUtils.writeInteger(buffer, (Integer) value);
}
- public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+ public Object readValueFromBuffer(ByteBuffer buffer)
{
return EncodingUtils.readInteger(buffer);
}
@@ -625,12 +624,12 @@ public enum AMQType
}
}
- public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+ public void writeValueImpl(Object value, ByteBuffer buffer)
{
EncodingUtils.writeLong(buffer, (Long) value);
}
- public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+ public Object readValueFromBuffer(ByteBuffer buffer)
{
return EncodingUtils.readLong(buffer);
}
@@ -660,12 +659,12 @@ public enum AMQType
}
}
- public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+ public void writeValueImpl(Object value, ByteBuffer buffer)
{
EncodingUtils.writeFloat(buffer, (Float) value);
}
- public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+ public Object readValueFromBuffer(ByteBuffer buffer)
{
return EncodingUtils.readFloat(buffer);
}
@@ -699,12 +698,12 @@ public enum AMQType
}
}
- public void writeValueImpl(Object value, DataOutputStream buffer) throws IOException
+ public void writeValueImpl(Object value, ByteBuffer buffer)
{
EncodingUtils.writeDouble(buffer, (Double) value);
}
- public Object readValueFromBuffer(DataInputStream buffer) throws IOException
+ public Object readValueFromBuffer(ByteBuffer buffer)
{
return EncodingUtils.readDouble(buffer);
}
@@ -771,9 +770,9 @@ public enum AMQType
* @param value An instance of the type.
* @param buffer The byte buffer to write it to.
*/
- public void writeToBuffer(Object value, DataOutputStream buffer) throws IOException
+ public void writeToBuffer(Object value, ByteBuffer buffer)
{
- buffer.writeByte(identifier());
+ buffer.put(identifier());
writeValueImpl(value, buffer);
}
@@ -783,7 +782,7 @@ public enum AMQType
* @param value An instance of the type.
* @param buffer The byte buffer to write it to.
*/
- abstract void writeValueImpl(Object value, DataOutputStream buffer) throws IOException;
+ abstract void writeValueImpl(Object value, ByteBuffer buffer);
/**
* Reads an instance of the type from a specified byte buffer.
@@ -792,5 +791,5 @@ public enum AMQType
*
* @return An instance of the type.
*/
- abstract Object readValueFromBuffer(DataInputStream buffer) throws IOException;
+ abstract Object readValueFromBuffer(ByteBuffer buffer);
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java b/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java
index 1dbedca362..647d531476 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java
@@ -20,9 +20,8 @@
*/
package org.apache.qpid.framing;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
+import org.apache.mina.common.ByteBuffer;
+
import java.util.Date;
import java.util.Map;
import java.math.BigDecimal;
@@ -61,7 +60,7 @@ public class AMQTypedValue
_value = type.toNativeValue(value);
}
- private AMQTypedValue(AMQType type, DataInputStream buffer) throws IOException
+ private AMQTypedValue(AMQType type, ByteBuffer buffer)
{
_type = type;
_value = type.readValueFromBuffer(buffer);
@@ -77,7 +76,7 @@ public class AMQTypedValue
return _value;
}
- public void writeToBuffer(DataOutputStream buffer) throws IOException
+ public void writeToBuffer(ByteBuffer buffer)
{
_type.writeToBuffer(_value, buffer);
}
@@ -87,9 +86,9 @@ public class AMQTypedValue
return _type.getEncodingSize(_value);
}
- public static AMQTypedValue readFromBuffer(DataInputStream buffer) throws IOException
+ public static AMQTypedValue readFromBuffer(ByteBuffer buffer)
{
- AMQType type = AMQTypeMap.getType(buffer.readByte());
+ AMQType type = AMQTypeMap.getType(buffer.get());
return new AMQTypedValue(type, buffer);
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java b/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java
index 57622b5054..c7d89a9927 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java
@@ -20,9 +20,7 @@
*/
package org.apache.qpid.framing;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
+import org.apache.mina.common.ByteBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -37,6 +35,27 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti
private static final AMQShortString ZERO_STRING = null;
+ /**
+ * We store the encoded form when we decode the content header so that if we need to write it out without modifying
+ * it we can do so without incurring the expense of reencoding it
+ */
+ private byte[] _encodedForm;
+
+ /** Flag indicating whether the entire content header has been decoded yet */
+ private boolean _decoded = true;
+
+ /**
+ * We have some optimisations for partial decoding for maximum performance. The headers are used in the broker for
+ * routing in some cases so we can decode that separately.
+ */
+ private boolean _decodedHeaders = true;
+
+ /**
+ * We have some optimisations for partial decoding for maximum performance. The content type is used by all clients
+ * to determine the message type
+ */
+ private boolean _decodedContentType = true;
+
private AMQShortString _contentType;
private AMQShortString _encoding;
@@ -67,10 +86,10 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti
private int _propertyFlags = 0;
private static final int CONTENT_TYPE_MASK = 1 << 15;
- private static final int ENCODING_MASK = 1 << 14;
+ private static final int ENCONDING_MASK = 1 << 14;
private static final int HEADERS_MASK = 1 << 13;
private static final int DELIVERY_MODE_MASK = 1 << 12;
- private static final int PRIORITY_MASK = 1 << 11;
+ private static final int PROPRITY_MASK = 1 << 11;
private static final int CORRELATION_ID_MASK = 1 << 10;
private static final int REPLY_TO_MASK = 1 << 9;
private static final int EXPIRATION_MASK = 1 << 8;
@@ -82,11 +101,34 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti
private static final int CLUSTER_ID_MASK = 1 << 2;
+ /**
+ * This is 0_10 specific. We use this property to check if some message properties have been changed.
+ */
+ private boolean _hasBeenUpdated = false;
+
+ public boolean reset()
+ {
+ boolean result = _hasBeenUpdated;
+ _hasBeenUpdated = false;
+ return result;
+ }
+
+ public void updated()
+ {
+ _hasBeenUpdated = true;
+ }
+
public BasicContentHeaderProperties()
{ }
public int getPropertyListSize()
{
+ if (_encodedForm != null)
+ {
+ return _encodedForm.length;
+ }
+ else
+ {
int size = 0;
if ((_propertyFlags & (CONTENT_TYPE_MASK)) > 0)
@@ -94,7 +136,7 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti
size += EncodingUtils.encodedShortStringLength(_contentType);
}
- if ((_propertyFlags & ENCODING_MASK) > 0)
+ if ((_propertyFlags & ENCONDING_MASK) > 0)
{
size += EncodingUtils.encodedShortStringLength(_encoding);
}
@@ -109,7 +151,7 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti
size += 1;
}
- if ((_propertyFlags & PRIORITY_MASK) > 0)
+ if ((_propertyFlags & PROPRITY_MASK) > 0)
{
size += 1;
}
@@ -167,10 +209,23 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti
}
return size;
+ }
+ }
+
+ private void clearEncodedForm()
+ {
+ if (!_decoded && (_encodedForm != null))
+ {
+ // decode();
+ }
+
+ _encodedForm = null;
}
public void setPropertyFlags(int propertyFlags)
{
+ _hasBeenUpdated = true;
+ clearEncodedForm();
_propertyFlags = propertyFlags;
}
@@ -179,87 +234,94 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti
return _propertyFlags;
}
- public void writePropertyListPayload(DataOutputStream buffer) throws IOException
+ public void writePropertyListPayload(ByteBuffer buffer)
{
- if ((_propertyFlags & (CONTENT_TYPE_MASK)) != 0)
+ if (_encodedForm != null)
{
- EncodingUtils.writeShortStringBytes(buffer, _contentType);
+ buffer.put(_encodedForm);
}
-
- if ((_propertyFlags & ENCODING_MASK) != 0)
+ else
{
- EncodingUtils.writeShortStringBytes(buffer, _encoding);
- }
+ if ((_propertyFlags & (CONTENT_TYPE_MASK)) != 0)
+ {
+ EncodingUtils.writeShortStringBytes(buffer, _contentType);
+ }
- if ((_propertyFlags & HEADERS_MASK) != 0)
- {
- EncodingUtils.writeFieldTableBytes(buffer, _headers);
- }
+ if ((_propertyFlags & ENCONDING_MASK) != 0)
+ {
+ EncodingUtils.writeShortStringBytes(buffer, _encoding);
+ }
- if ((_propertyFlags & DELIVERY_MODE_MASK) != 0)
- {
- buffer.writeByte(_deliveryMode);
- }
+ if ((_propertyFlags & HEADERS_MASK) != 0)
+ {
+ EncodingUtils.writeFieldTableBytes(buffer, _headers);
+ }
- if ((_propertyFlags & PRIORITY_MASK) != 0)
- {
- buffer.writeByte(_priority);
- }
+ if ((_propertyFlags & DELIVERY_MODE_MASK) != 0)
+ {
+ buffer.put(_deliveryMode);
+ }
- if ((_propertyFlags & CORRELATION_ID_MASK) != 0)
- {
- EncodingUtils.writeShortStringBytes(buffer, _correlationId);
- }
+ if ((_propertyFlags & PROPRITY_MASK) != 0)
+ {
+ buffer.put(_priority);
+ }
- if ((_propertyFlags & REPLY_TO_MASK) != 0)
- {
- EncodingUtils.writeShortStringBytes(buffer, _replyTo);
- }
+ if ((_propertyFlags & CORRELATION_ID_MASK) != 0)
+ {
+ EncodingUtils.writeShortStringBytes(buffer, _correlationId);
+ }
- if ((_propertyFlags & EXPIRATION_MASK) != 0)
- {
- if (_expiration == 0L)
+ if ((_propertyFlags & REPLY_TO_MASK) != 0)
{
- EncodingUtils.writeShortStringBytes(buffer, ZERO_STRING);
+ EncodingUtils.writeShortStringBytes(buffer, _replyTo);
}
- else
+
+ if ((_propertyFlags & EXPIRATION_MASK) != 0)
{
- EncodingUtils.writeShortStringBytes(buffer, String.valueOf(_expiration));
+ if (_expiration == 0L)
+ {
+ EncodingUtils.writeShortStringBytes(buffer, ZERO_STRING);
+ }
+ else
+ {
+ EncodingUtils.writeShortStringBytes(buffer, String.valueOf(_expiration));
+ }
}
- }
- if ((_propertyFlags & MESSAGE_ID_MASK) != 0)
- {
- EncodingUtils.writeShortStringBytes(buffer, _messageId);
- }
+ if ((_propertyFlags & MESSAGE_ID_MASK) != 0)
+ {
+ EncodingUtils.writeShortStringBytes(buffer, _messageId);
+ }
- if ((_propertyFlags & TIMESTAMP_MASK) != 0)
- {
- EncodingUtils.writeTimestamp(buffer, _timestamp);
- }
+ if ((_propertyFlags & TIMESTAMP_MASK) != 0)
+ {
+ EncodingUtils.writeTimestamp(buffer, _timestamp);
+ }
- if ((_propertyFlags & TYPE_MASK) != 0)
- {
- EncodingUtils.writeShortStringBytes(buffer, _type);
- }
+ if ((_propertyFlags & TYPE_MASK) != 0)
+ {
+ EncodingUtils.writeShortStringBytes(buffer, _type);
+ }
- if ((_propertyFlags & USER_ID_MASK) != 0)
- {
- EncodingUtils.writeShortStringBytes(buffer, _userId);
- }
+ if ((_propertyFlags & USER_ID_MASK) != 0)
+ {
+ EncodingUtils.writeShortStringBytes(buffer, _userId);
+ }
- if ((_propertyFlags & APPLICATION_ID_MASK) != 0)
- {
- EncodingUtils.writeShortStringBytes(buffer, _appId);
- }
+ if ((_propertyFlags & APPLICATION_ID_MASK) != 0)
+ {
+ EncodingUtils.writeShortStringBytes(buffer, _appId);
+ }
- if ((_propertyFlags & CLUSTER_ID_MASK) != 0)
- {
- EncodingUtils.writeShortStringBytes(buffer, _clusterId);
+ if ((_propertyFlags & CLUSTER_ID_MASK) != 0)
+ {
+ EncodingUtils.writeShortStringBytes(buffer, _clusterId);
+ }
}
}
- public void populatePropertiesFromBuffer(DataInputStream buffer, int propertyFlags, int size) throws AMQFrameDecodingException, IOException
+ public void populatePropertiesFromBuffer(ByteBuffer buffer, int propertyFlags, int size) throws AMQFrameDecodingException
{
_propertyFlags = propertyFlags;
@@ -269,18 +331,25 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti
}
decode(buffer);
+ /*_encodedForm = new byte[size];
+ buffer.get(_encodedForm, 0, size);
+ _decoded = false;
+ _decodedHeaders = false;
+ _decodedContentType = false;*/
}
- private void decode(DataInputStream buffer) throws IOException, AMQFrameDecodingException
+ private void decode(ByteBuffer buffer)
{
// ByteBuffer buffer = ByteBuffer.wrap(_encodedForm);
-
+ int pos = buffer.position();
+ try
+ {
if ((_propertyFlags & (CONTENT_TYPE_MASK)) != 0)
{
_contentType = EncodingUtils.readAMQShortString(buffer);
}
- if ((_propertyFlags & ENCODING_MASK) != 0)
+ if ((_propertyFlags & ENCONDING_MASK) != 0)
{
_encoding = EncodingUtils.readAMQShortString(buffer);
}
@@ -292,12 +361,12 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti
if ((_propertyFlags & DELIVERY_MODE_MASK) != 0)
{
- _deliveryMode = buffer.readByte();
+ _deliveryMode = buffer.get();
}
- if ((_propertyFlags & PRIORITY_MASK) != 0)
+ if ((_propertyFlags & PROPRITY_MASK) != 0)
{
- _priority = buffer.readByte();
+ _priority = buffer.get();
}
if ((_propertyFlags & CORRELATION_ID_MASK) != 0)
@@ -344,29 +413,116 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti
{
_clusterId = EncodingUtils.readAMQShortString(buffer);
}
+ }
+ catch (AMQFrameDecodingException e)
+ {
+ throw new RuntimeException("Error in content header data: " + e, e);
+ }
+ final int endPos = buffer.position();
+ buffer.position(pos);
+ final int len = endPos - pos;
+ _encodedForm = new byte[len];
+ final int limit = buffer.limit();
+ buffer.limit(endPos);
+ buffer.get(_encodedForm, 0, len);
+ buffer.limit(limit);
+ buffer.position(endPos);
+ _decoded = true;
+ }
+ private void decodeUpToHeaders()
+ {
+ ByteBuffer buffer = ByteBuffer.wrap(_encodedForm);
+ try
+ {
+ if ((_propertyFlags & (CONTENT_TYPE_MASK)) != 0)
+ {
+ byte length = buffer.get();
+ buffer.skip(length);
+ }
+
+ if ((_propertyFlags & ENCONDING_MASK) != 0)
+ {
+ byte length = buffer.get();
+ buffer.skip(length);
+ }
+
+ if ((_propertyFlags & HEADERS_MASK) != 0)
+ {
+ _headers = EncodingUtils.readFieldTable(buffer);
+
+ }
+
+ _decodedHeaders = true;
+ }
+ catch (AMQFrameDecodingException e)
+ {
+ throw new RuntimeException("Error in content header data: " + e, e);
+ }
}
+ private void decodeUpToContentType()
+ {
+ ByteBuffer buffer = ByteBuffer.wrap(_encodedForm);
+
+ if ((_propertyFlags & (CONTENT_TYPE_MASK)) != 0)
+ {
+ _contentType = EncodingUtils.readAMQShortString(buffer);
+ }
+
+ _decodedContentType = true;
+ }
+
+ private void decodeIfNecessary()
+ {
+ if (!_decoded)
+ {
+ // decode();
+ }
+ }
+
+ private void decodeHeadersIfNecessary()
+ {
+ if (!_decoded && !_decodedHeaders)
+ {
+ decodeUpToHeaders();
+ }
+ }
+
+ private void decodeContentTypeIfNecessary()
+ {
+ if (!_decoded && !_decodedContentType)
+ {
+ decodeUpToContentType();
+ }
+ }
public AMQShortString getContentType()
{
+ decodeContentTypeIfNecessary();
+
return _contentType;
}
public String getContentTypeAsString()
{
+ decodeContentTypeIfNecessary();
+
return (_contentType == null) ? null : _contentType.toString();
}
public void setContentType(AMQShortString contentType)
{
+ _hasBeenUpdated = true;
+ clearEncodedForm();
_propertyFlags |= (CONTENT_TYPE_MASK);
_contentType = contentType;
}
public void setContentType(String contentType)
{
+ _hasBeenUpdated = true;
setContentType((contentType == null) ? null : new AMQShortString(contentType));
}
@@ -378,23 +534,31 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti
public AMQShortString getEncoding()
{
+ decodeIfNecessary();
+
return _encoding;
}
public void setEncoding(String encoding)
{
- _propertyFlags |= ENCODING_MASK;
+ _hasBeenUpdated = true;
+ clearEncodedForm();
+ _propertyFlags |= ENCONDING_MASK;
_encoding = (encoding == null) ? null : new AMQShortString(encoding);
}
public void setEncoding(AMQShortString encoding)
{
- _propertyFlags |= ENCODING_MASK;
+ _hasBeenUpdated = true;
+ clearEncodedForm();
+ _propertyFlags |= ENCONDING_MASK;
_encoding = encoding;
}
public FieldTable getHeaders()
{
+ decodeHeadersIfNecessary();
+
if (_headers == null)
{
setHeaders(FieldTableFactory.newFieldTable());
@@ -405,146 +569,191 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti
public void setHeaders(FieldTable headers)
{
+ _hasBeenUpdated = true;
+ clearEncodedForm();
_propertyFlags |= HEADERS_MASK;
_headers = headers;
}
public byte getDeliveryMode()
{
+ decodeIfNecessary();
+
return _deliveryMode;
}
public void setDeliveryMode(byte deliveryMode)
{
+ clearEncodedForm();
_propertyFlags |= DELIVERY_MODE_MASK;
_deliveryMode = deliveryMode;
}
public byte getPriority()
{
+ decodeIfNecessary();
+
return _priority;
}
public void setPriority(byte priority)
{
- _propertyFlags |= PRIORITY_MASK;
+ clearEncodedForm();
+ _propertyFlags |= PROPRITY_MASK;
_priority = priority;
}
public AMQShortString getCorrelationId()
{
+ decodeIfNecessary();
+
return _correlationId;
}
public String getCorrelationIdAsString()
{
+ decodeIfNecessary();
+
return (_correlationId == null) ? null : _correlationId.toString();
}
public void setCorrelationId(String correlationId)
{
+ _hasBeenUpdated = true;
setCorrelationId((correlationId == null) ? null : new AMQShortString(correlationId));
}
public void setCorrelationId(AMQShortString correlationId)
{
+ _hasBeenUpdated = true;
+ clearEncodedForm();
_propertyFlags |= CORRELATION_ID_MASK;
_correlationId = correlationId;
}
public String getReplyToAsString()
{
+ decodeIfNecessary();
+
return (_replyTo == null) ? null : _replyTo.toString();
}
public AMQShortString getReplyTo()
{
+ decodeIfNecessary();
+
return _replyTo;
}
public void setReplyTo(String replyTo)
{
+ _hasBeenUpdated = true;
setReplyTo((replyTo == null) ? null : new AMQShortString(replyTo));
}
public void setReplyTo(AMQShortString replyTo)
{
+ _hasBeenUpdated = true;
+ clearEncodedForm();
_propertyFlags |= REPLY_TO_MASK;
_replyTo = replyTo;
}
public long getExpiration()
{
+ decodeIfNecessary();
return _expiration;
}
public void setExpiration(long expiration)
{
+ clearEncodedForm();
_propertyFlags |= EXPIRATION_MASK;
_expiration = expiration;
}
public AMQShortString getMessageId()
{
+ decodeIfNecessary();
+
return _messageId;
}
public String getMessageIdAsString()
{
+ decodeIfNecessary();
+
return (_messageId == null) ? null : _messageId.toString();
}
public void setMessageId(String messageId)
{
+ _hasBeenUpdated = true;
+ clearEncodedForm();
_propertyFlags |= MESSAGE_ID_MASK;
_messageId = (messageId == null) ? null : new AMQShortString(messageId);
}
public void setMessageId(AMQShortString messageId)
{
+ _hasBeenUpdated = true;
+ clearEncodedForm();
_propertyFlags |= MESSAGE_ID_MASK;
_messageId = messageId;
}
public long getTimestamp()
{
+ decodeIfNecessary();
return _timestamp;
}
public void setTimestamp(long timestamp)
{
+ clearEncodedForm();
_propertyFlags |= TIMESTAMP_MASK;
_timestamp = timestamp;
}
public String getTypeAsString()
{
+ decodeIfNecessary();
+
return (_type == null) ? null : _type.toString();
}
public AMQShortString getType()
{
+ decodeIfNecessary();
+
return _type;
}
public void setType(String type)
{
+ _hasBeenUpdated = true;
setType((type == null) ? null : new AMQShortString(type));
}
public void setType(AMQShortString type)
{
+ _hasBeenUpdated = true;
+ clearEncodedForm();
_propertyFlags |= TYPE_MASK;
_type = type;
}
public String getUserIdAsString()
{
+ decodeIfNecessary();
+
return (_userId == null) ? null : _userId.toString();
}
public AMQShortString getUserId()
{
+ decodeIfNecessary();
+
return _userId;
}
@@ -555,48 +764,65 @@ public class BasicContentHeaderProperties implements CommonContentHeaderProperti
public void setUserId(AMQShortString userId)
{
+ _hasBeenUpdated = true;
+ clearEncodedForm();
_propertyFlags |= USER_ID_MASK;
_userId = userId;
}
public String getAppIdAsString()
{
+ decodeIfNecessary();
+
return (_appId == null) ? null : _appId.toString();
}
public AMQShortString getAppId()
{
+ decodeIfNecessary();
+
return _appId;
}
public void setAppId(String appId)
{
+ _hasBeenUpdated = true;
setAppId((appId == null) ? null : new AMQShortString(appId));
}
public void setAppId(AMQShortString appId)
{
+ _hasBeenUpdated = true;
+ clearEncodedForm();
_propertyFlags |= APPLICATION_ID_MASK;
_appId = appId;
+ _hasBeenUpdated = true;
}
public String getClusterIdAsString()
{
+ _hasBeenUpdated = true;
+ decodeIfNecessary();
return (_clusterId == null) ? null : _clusterId.toString();
}
public AMQShortString getClusterId()
{
+ _hasBeenUpdated = true;
+ decodeIfNecessary();
return _clusterId;
}
public void setClusterId(String clusterId)
{
+ _hasBeenUpdated = true;
setClusterId((clusterId == null) ? null : new AMQShortString(clusterId));
}
public void setClusterId(AMQShortString clusterId)
{
+ _hasBeenUpdated = true;
+ clearEncodedForm();
_propertyFlags |= CLUSTER_ID_MASK;
_clusterId = clusterId;
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/BodyFactory.java b/java/common/src/main/java/org/apache/qpid/framing/BodyFactory.java
index f9580d82b1..59646577e1 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/BodyFactory.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/BodyFactory.java
@@ -20,13 +20,12 @@
*/
package org.apache.qpid.framing;
-import java.io.DataInputStream;
-import java.io.IOException;
+import org.apache.mina.common.ByteBuffer;
/**
* Any class that is capable of turning a stream of bytes into an AMQ structure must implement this interface.
*/
public interface BodyFactory
{
- AMQBody createBody(DataInputStream in, long bodySize) throws AMQFrameDecodingException, IOException;
+ AMQBody createBody(ByteBuffer in, long bodySize) throws AMQFrameDecodingException;
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/CompositeAMQDataBlock.java b/java/common/src/main/java/org/apache/qpid/framing/CompositeAMQDataBlock.java
index 15bc20c52d..94030f383e 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/CompositeAMQDataBlock.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/CompositeAMQDataBlock.java
@@ -20,8 +20,7 @@
*/
package org.apache.qpid.framing;
-import java.io.DataOutputStream;
-import java.io.IOException;
+import org.apache.mina.common.ByteBuffer;
public class CompositeAMQDataBlock extends AMQDataBlock implements EncodableAMQDataBlock
{
@@ -50,7 +49,7 @@ public class CompositeAMQDataBlock extends AMQDataBlock implements EncodableAMQD
return frameSize;
}
- public void writePayload(DataOutputStream buffer) throws IOException
+ public void writePayload(ByteBuffer buffer)
{
for (int i = 0; i < _blocks.length; i++)
{
diff --git a/java/common/src/main/java/org/apache/qpid/framing/ContentBody.java b/java/common/src/main/java/org/apache/qpid/framing/ContentBody.java
index aedb35f92a..9d39f8aa86 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/ContentBody.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/ContentBody.java
@@ -20,10 +20,7 @@
*/
package org.apache.qpid.framing;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-
+import org.apache.mina.common.ByteBuffer;
import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
import org.apache.qpid.AMQException;
@@ -31,22 +28,27 @@ public class ContentBody implements AMQBody
{
public static final byte TYPE = 3;
- public byte[] _payload;
+ public ByteBuffer payload;
public ContentBody()
{
}
- public ContentBody(DataInputStream buffer, long size) throws AMQFrameDecodingException, IOException
+ public ContentBody(ByteBuffer buffer, long size) throws AMQFrameDecodingException
{
- _payload = new byte[(int)size];
- buffer.read(_payload);
+ if (size > 0)
+ {
+ payload = buffer.slice();
+ payload.limit((int) size);
+ buffer.skip((int) size);
+ }
+
}
- public ContentBody(byte[] payload)
+ public ContentBody(ByteBuffer payload)
{
- _payload = payload;
+ this.payload = payload;
}
public byte getFrameType()
@@ -56,12 +58,23 @@ public class ContentBody implements AMQBody
public int getSize()
{
- return _payload == null ? 0 : _payload.length;
+ return (payload == null ? 0 : payload.limit());
}
- public void writePayload(DataOutputStream buffer) throws IOException
+ public void writePayload(ByteBuffer buffer)
{
- buffer.write(_payload);
+ if (payload != null)
+ {
+ if(payload.isDirect() || payload.isReadOnly())
+ {
+ ByteBuffer copy = payload.duplicate();
+ buffer.put(copy.rewind());
+ }
+ else
+ {
+ buffer.put(payload.array(),payload.arrayOffset(),payload.limit());
+ }
+ }
}
public void handle(final int channelId, final AMQVersionAwareProtocolSession session)
@@ -70,18 +83,32 @@ public class ContentBody implements AMQBody
session.contentBodyReceived(channelId, this);
}
- protected void populateFromBuffer(DataInputStream buffer, long size) throws AMQFrameDecodingException, IOException
+ protected void populateFromBuffer(ByteBuffer buffer, long size) throws AMQFrameDecodingException
{
if (size > 0)
{
- _payload = new byte[(int)size];
- buffer.read(_payload);
+ payload = buffer.slice();
+ payload.limit((int) size);
+ buffer.skip((int) size);
}
}
public void reduceBufferToFit()
{
+ if (payload != null && (payload.remaining() < payload.capacity() / 2))
+ {
+ int size = payload.limit();
+ ByteBuffer newPayload = ByteBuffer.allocate(size);
+
+ newPayload.put(payload);
+ newPayload.flip();
+
+ //reduce reference count on payload
+ payload.release();
+
+ payload = newPayload;
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/ContentBodyFactory.java b/java/common/src/main/java/org/apache/qpid/framing/ContentBodyFactory.java
index a0b030ab6b..c42995d148 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/ContentBodyFactory.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/ContentBodyFactory.java
@@ -20,8 +20,7 @@
*/
package org.apache.qpid.framing;
-import java.io.DataInputStream;
-import java.io.IOException;
+import org.apache.mina.common.ByteBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -42,7 +41,7 @@ public class ContentBodyFactory implements BodyFactory
_log.debug("Creating content body factory");
}
- public AMQBody createBody(DataInputStream in, long bodySize) throws AMQFrameDecodingException, IOException
+ public AMQBody createBody(ByteBuffer in, long bodySize) throws AMQFrameDecodingException
{
return new ContentBody(in, bodySize);
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBody.java b/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBody.java
index 18d0f26152..83e5a7e341 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBody.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBody.java
@@ -20,10 +20,7 @@
*/
package org.apache.qpid.framing;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-
+import org.apache.mina.common.ByteBuffer;
import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
import org.apache.qpid.AMQException;
@@ -39,18 +36,18 @@ public class ContentHeaderBody implements AMQBody
public long bodySize;
/** must never be null */
- private ContentHeaderProperties properties;
+ public ContentHeaderProperties properties;
public ContentHeaderBody()
{
}
- public ContentHeaderBody(DataInputStream buffer, long size) throws AMQFrameDecodingException, IOException
+ public ContentHeaderBody(ByteBuffer buffer, long size) throws AMQFrameDecodingException
{
- classId = buffer.readUnsignedShort();
- weight = buffer.readUnsignedShort();
- bodySize = buffer.readLong();
- int propertyFlags = buffer.readUnsignedShort();
+ classId = buffer.getUnsignedShort();
+ weight = buffer.getUnsignedShort();
+ bodySize = buffer.getLong();
+ int propertyFlags = buffer.getUnsignedShort();
ContentHeaderPropertiesFactory factory = ContentHeaderPropertiesFactory.getInstance();
properties = factory.createContentHeaderProperties(classId, propertyFlags, buffer, (int)size - 14);
@@ -75,13 +72,13 @@ public class ContentHeaderBody implements AMQBody
return TYPE;
}
- protected void populateFromBuffer(DataInputStream buffer, long size)
- throws AMQFrameDecodingException, AMQProtocolVersionException, IOException
+ protected void populateFromBuffer(ByteBuffer buffer, long size)
+ throws AMQFrameDecodingException, AMQProtocolVersionException
{
- classId = buffer.readUnsignedShort();
- weight = buffer.readUnsignedShort();
- bodySize = buffer.readLong();
- int propertyFlags = buffer.readUnsignedShort();
+ classId = buffer.getUnsignedShort();
+ weight = buffer.getUnsignedShort();
+ bodySize = buffer.getLong();
+ int propertyFlags = buffer.getUnsignedShort();
ContentHeaderPropertiesFactory factory = ContentHeaderPropertiesFactory.getInstance();
properties = factory.createContentHeaderProperties(classId, propertyFlags, buffer, (int)size - 14);
}
@@ -93,8 +90,8 @@ public class ContentHeaderBody implements AMQBody
* @return
* @throws AMQFrameDecodingException
*/
- public static ContentHeaderBody createFromBuffer(DataInputStream buffer, long size)
- throws AMQFrameDecodingException, AMQProtocolVersionException, IOException
+ public static ContentHeaderBody createFromBuffer(ByteBuffer buffer, long size)
+ throws AMQFrameDecodingException, AMQProtocolVersionException
{
ContentHeaderBody body = new ContentHeaderBody(buffer, size);
@@ -106,11 +103,11 @@ public class ContentHeaderBody implements AMQBody
return 2 + 2 + 8 + 2 + properties.getPropertyListSize();
}
- public void writePayload(DataOutputStream buffer) throws IOException
+ public void writePayload(ByteBuffer buffer)
{
EncodingUtils.writeUnsignedShort(buffer, classId);
EncodingUtils.writeUnsignedShort(buffer, weight);
- buffer.writeLong(bodySize);
+ buffer.putLong(bodySize);
EncodingUtils.writeUnsignedShort(buffer, properties.getPropertyFlags());
properties.writePropertyListPayload(buffer);
}
@@ -131,25 +128,4 @@ public class ContentHeaderBody implements AMQBody
{
return new AMQFrame(channelId, body);
}
-
- public ContentHeaderProperties getProperties()
- {
- return properties;
- }
-
- public void setProperties(ContentHeaderProperties props)
- {
- properties = props;
- }
-
- @Override
- public String toString()
- {
- return "ContentHeaderBody{" +
- "classId=" + classId +
- ", weight=" + weight +
- ", bodySize=" + bodySize +
- ", properties=" + properties +
- '}';
- }
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBodyFactory.java b/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBodyFactory.java
index a474e337b7..8d5e2f9fb4 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBodyFactory.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderBodyFactory.java
@@ -20,8 +20,7 @@
*/
package org.apache.qpid.framing;
-import java.io.DataInputStream;
-import java.io.IOException;
+import org.apache.mina.common.ByteBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -42,7 +41,7 @@ public class ContentHeaderBodyFactory implements BodyFactory
_log.debug("Creating content header body factory");
}
- public AMQBody createBody(DataInputStream in, long bodySize) throws AMQFrameDecodingException, IOException
+ public AMQBody createBody(ByteBuffer in, long bodySize) throws AMQFrameDecodingException
{
// all content headers are the same - it is only the properties that differ.
// the content header body further delegates construction of properties
diff --git a/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderProperties.java b/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderProperties.java
index 237929f9a3..7ef538cfdc 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderProperties.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderProperties.java
@@ -20,10 +20,7 @@
*/
package org.apache.qpid.framing;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-
+import org.apache.mina.common.ByteBuffer;
/**
* There will be an implementation of this interface for each content type. All content types have associated
@@ -35,7 +32,7 @@ public interface ContentHeaderProperties
* Writes the property list to the buffer, in a suitably encoded form.
* @param buffer The buffer to write to
*/
- void writePropertyListPayload(DataOutputStream buffer) throws IOException;
+ void writePropertyListPayload(ByteBuffer buffer);
/**
* Populates the properties from buffer.
@@ -43,8 +40,8 @@ public interface ContentHeaderProperties
* @param propertyFlags he property flags.
* @throws AMQFrameDecodingException when the buffer does not contain valid data
*/
- void populatePropertiesFromBuffer(DataInputStream buffer, int propertyFlags, int size)
- throws AMQFrameDecodingException, IOException;
+ void populatePropertiesFromBuffer(ByteBuffer buffer, int propertyFlags, int size)
+ throws AMQFrameDecodingException;
/**
* @return the size of the encoded property list in bytes.
@@ -59,4 +56,5 @@ public interface ContentHeaderProperties
*/
int getPropertyFlags();
+ void updated();
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderPropertiesFactory.java b/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderPropertiesFactory.java
index 43ee8cd1f1..46189b63d7 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderPropertiesFactory.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/ContentHeaderPropertiesFactory.java
@@ -20,8 +20,7 @@
*/
package org.apache.qpid.framing;
-import java.io.DataInputStream;
-import java.io.IOException;
+import org.apache.mina.common.ByteBuffer;
import org.apache.qpid.framing.amqp_8_0.BasicConsumeBodyImpl;
@@ -39,8 +38,8 @@ public class ContentHeaderPropertiesFactory
}
public ContentHeaderProperties createContentHeaderProperties(int classId, int propertyFlags,
- DataInputStream buffer, int size)
- throws AMQFrameDecodingException, IOException
+ ByteBuffer buffer, int size)
+ throws AMQFrameDecodingException
{
ContentHeaderProperties properties;
// AMQP version change: "Hardwired" version to major=8, minor=0
diff --git a/java/common/src/main/java/org/apache/qpid/framing/DeferredDataBlock.java b/java/common/src/main/java/org/apache/qpid/framing/DeferredDataBlock.java
new file mode 100644
index 0000000000..f6795ff200
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/framing/DeferredDataBlock.java
@@ -0,0 +1,50 @@
+package org.apache.qpid.framing;
+
+import org.apache.mina.common.ByteBuffer;
+
+/*
+*
+* Licensed to the Apache Software Foundation (ASF) under one
+* or more contributor license agreements. See the NOTICE file
+* distributed with this work for additional information
+* regarding copyright ownership. The ASF licenses this file
+* to you under the Apache License, Version 2.0 (the
+* "License"); you may not use this file except in compliance
+* with the License. You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied. See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*
+*/
+public abstract class DeferredDataBlock extends AMQDataBlock
+{
+ private AMQDataBlock _underlyingDataBlock;
+
+
+ public long getSize()
+ {
+ if(_underlyingDataBlock == null)
+ {
+ _underlyingDataBlock = createAMQDataBlock();
+ }
+ return _underlyingDataBlock.getSize();
+ }
+
+ public void writePayload(ByteBuffer buffer)
+ {
+ if(_underlyingDataBlock == null)
+ {
+ _underlyingDataBlock = createAMQDataBlock();
+ }
+ _underlyingDataBlock.writePayload(buffer);
+ }
+
+ abstract protected AMQDataBlock createAMQDataBlock();
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/EncodingUtils.java b/java/common/src/main/java/org/apache/qpid/framing/EncodingUtils.java
index 2d7e27405c..6425f8c591 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/EncodingUtils.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/EncodingUtils.java
@@ -20,12 +20,11 @@
*/
package org.apache.qpid.framing;
-import java.io.*;
+import org.apache.mina.common.ByteBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.nio.ByteBuffer;
import java.nio.charset.Charset;
public class EncodingUtils
@@ -219,7 +218,7 @@ public class EncodingUtils
return 0;
}
- public static void writeShortStringBytes(DataOutputStream buffer, String s) throws IOException
+ public static void writeShortStringBytes(ByteBuffer buffer, String s)
{
if (s != null)
{
@@ -232,18 +231,18 @@ public class EncodingUtils
// TODO: check length fits in an unsigned byte
writeUnsignedByte(buffer, (short)encodedString.length);
- buffer.write(encodedString);
+ buffer.put(encodedString);
}
else
{
// really writing out unsigned byte
- buffer.write((byte) 0);
+ buffer.put((byte) 0);
}
}
- public static void writeShortStringBytes(DataOutputStream buffer, AMQShortString s) throws IOException
+ public static void writeShortStringBytes(ByteBuffer buffer, AMQShortString s)
{
if (s != null)
{
@@ -253,11 +252,11 @@ public class EncodingUtils
else
{
// really writing out unsigned byte
- buffer.write((byte) 0);
+ buffer.put((byte) 0);
}
}
- public static void writeLongStringBytes(DataOutputStream buffer, String s) throws IOException
+ public static void writeLongStringBytes(ByteBuffer buffer, String s)
{
assert (s == null) || (s.length() <= 0xFFFE);
if (s != null)
@@ -271,7 +270,7 @@ public class EncodingUtils
encodedString[i] = (byte) cha[i];
}
- buffer.write(encodedString);
+ buffer.put(encodedString);
}
else
{
@@ -279,7 +278,7 @@ public class EncodingUtils
}
}
- public static void writeLongStringBytes(DataOutputStream buffer, char[] s) throws IOException
+ public static void writeLongStringBytes(ByteBuffer buffer, char[] s)
{
assert (s == null) || (s.length <= 0xFFFE);
if (s != null)
@@ -292,7 +291,7 @@ public class EncodingUtils
encodedString[i] = (byte) s[i];
}
- buffer.write(encodedString);
+ buffer.put(encodedString);
}
else
{
@@ -300,13 +299,13 @@ public class EncodingUtils
}
}
- public static void writeLongStringBytes(DataOutputStream buffer, byte[] bytes) throws IOException
+ public static void writeLongStringBytes(ByteBuffer buffer, byte[] bytes)
{
assert (bytes == null) || (bytes.length <= 0xFFFE);
if (bytes != null)
{
writeUnsignedInteger(buffer, bytes.length);
- buffer.write(bytes);
+ buffer.put(bytes);
}
else
{
@@ -314,24 +313,24 @@ public class EncodingUtils
}
}
- public static void writeUnsignedByte(DataOutputStream buffer, short b) throws IOException
+ public static void writeUnsignedByte(ByteBuffer buffer, short b)
{
byte bv = (byte) b;
- buffer.write(bv);
+ buffer.put(bv);
}
- public static void writeUnsignedShort(DataOutputStream buffer, int s) throws IOException
+ public static void writeUnsignedShort(ByteBuffer buffer, int s)
{
// TODO: Is this comparison safe? Do I need to cast RHS to long?
if (s < Short.MAX_VALUE)
{
- buffer.writeShort(s);
+ buffer.putShort((short) s);
}
else
{
short sv = (short) s;
- buffer.write((byte) (0xFF & (sv >> 8)));
- buffer.write((byte) (0xFF & sv));
+ buffer.put((byte) (0xFF & (sv >> 8)));
+ buffer.put((byte) (0xFF & sv));
}
}
@@ -340,12 +339,12 @@ public class EncodingUtils
return 4;
}
- public static void writeUnsignedInteger(DataOutputStream buffer, long l) throws IOException
+ public static void writeUnsignedInteger(ByteBuffer buffer, long l)
{
// TODO: Is this comparison safe? Do I need to cast RHS to long?
if (l < Integer.MAX_VALUE)
{
- buffer.writeInt((int) l);
+ buffer.putInt((int) l);
}
else
{
@@ -353,14 +352,14 @@ public class EncodingUtils
// FIXME: This *may* go faster if we build this into a local 4-byte array and then
// put the array in a single call.
- buffer.write((byte) (0xFF & (iv >> 24)));
- buffer.write((byte) (0xFF & (iv >> 16)));
- buffer.write((byte) (0xFF & (iv >> 8)));
- buffer.write((byte) (0xFF & iv));
+ buffer.put((byte) (0xFF & (iv >> 24)));
+ buffer.put((byte) (0xFF & (iv >> 16)));
+ buffer.put((byte) (0xFF & (iv >> 8)));
+ buffer.put((byte) (0xFF & iv));
}
}
- public static void writeFieldTableBytes(DataOutputStream buffer, FieldTable table) throws IOException
+ public static void writeFieldTableBytes(ByteBuffer buffer, FieldTable table)
{
if (table != null)
{
@@ -372,12 +371,12 @@ public class EncodingUtils
}
}
- public static void writeContentBytes(DataOutputStream buffer, Content content)
+ public static void writeContentBytes(ByteBuffer buffer, Content content)
{
// TODO: New Content class required for AMQP 0-9.
}
- public static void writeBooleans(DataOutputStream buffer, boolean[] values) throws IOException
+ public static void writeBooleans(ByteBuffer buffer, boolean[] values)
{
byte packedValue = 0;
for (int i = 0; i < values.length; i++)
@@ -388,16 +387,16 @@ public class EncodingUtils
}
}
- buffer.write(packedValue);
+ buffer.put(packedValue);
}
- public static void writeBooleans(DataOutputStream buffer, boolean value) throws IOException
+ public static void writeBooleans(ByteBuffer buffer, boolean value)
{
- buffer.write(value ? (byte) 1 : (byte) 0);
+ buffer.put(value ? (byte) 1 : (byte) 0);
}
- public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1) throws IOException
+ public static void writeBooleans(ByteBuffer buffer, boolean value0, boolean value1)
{
byte packedValue = value0 ? (byte) 1 : (byte) 0;
@@ -406,10 +405,10 @@ public class EncodingUtils
packedValue = (byte) (packedValue | (byte) (1 << 1));
}
- buffer.write(packedValue);
+ buffer.put(packedValue);
}
- public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2) throws IOException
+ public static void writeBooleans(ByteBuffer buffer, boolean value0, boolean value1, boolean value2)
{
byte packedValue = value0 ? (byte) 1 : (byte) 0;
@@ -423,10 +422,10 @@ public class EncodingUtils
packedValue = (byte) (packedValue | (byte) (1 << 2));
}
- buffer.write(packedValue);
+ buffer.put(packedValue);
}
- public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2, boolean value3) throws IOException
+ public static void writeBooleans(ByteBuffer buffer, boolean value0, boolean value1, boolean value2, boolean value3)
{
byte packedValue = value0 ? (byte) 1 : (byte) 0;
@@ -445,11 +444,11 @@ public class EncodingUtils
packedValue = (byte) (packedValue | (byte) (1 << 3));
}
- buffer.write(packedValue);
+ buffer.put(packedValue);
}
- public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2, boolean value3,
- boolean value4) throws IOException
+ public static void writeBooleans(ByteBuffer buffer, boolean value0, boolean value1, boolean value2, boolean value3,
+ boolean value4)
{
byte packedValue = value0 ? (byte) 1 : (byte) 0;
@@ -473,11 +472,11 @@ public class EncodingUtils
packedValue = (byte) (packedValue | (byte) (1 << 4));
}
- buffer.write(packedValue);
+ buffer.put(packedValue);
}
- public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2, boolean value3,
- boolean value4, boolean value5) throws IOException
+ public static void writeBooleans(ByteBuffer buffer, boolean value0, boolean value1, boolean value2, boolean value3,
+ boolean value4, boolean value5)
{
byte packedValue = value0 ? (byte) 1 : (byte) 0;
@@ -506,11 +505,11 @@ public class EncodingUtils
packedValue = (byte) (packedValue | (byte) (1 << 5));
}
- buffer.write(packedValue);
+ buffer.put(packedValue);
}
- public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2, boolean value3,
- boolean value4, boolean value5, boolean value6) throws IOException
+ public static void writeBooleans(ByteBuffer buffer, boolean value0, boolean value1, boolean value2, boolean value3,
+ boolean value4, boolean value5, boolean value6)
{
byte packedValue = value0 ? (byte) 1 : (byte) 0;
@@ -544,11 +543,11 @@ public class EncodingUtils
packedValue = (byte) (packedValue | (byte) (1 << 6));
}
- buffer.write(packedValue);
+ buffer.put(packedValue);
}
- public static void writeBooleans(DataOutputStream buffer, boolean value0, boolean value1, boolean value2, boolean value3,
- boolean value4, boolean value5, boolean value6, boolean value7) throws IOException
+ public static void writeBooleans(ByteBuffer buffer, boolean value0, boolean value1, boolean value2, boolean value3,
+ boolean value4, boolean value5, boolean value6, boolean value7)
{
byte packedValue = value0 ? (byte) 1 : (byte) 0;
@@ -587,7 +586,7 @@ public class EncodingUtils
packedValue = (byte) (packedValue | (byte) (1 << 7));
}
- buffer.write(packedValue);
+ buffer.put(packedValue);
}
/**
@@ -596,12 +595,12 @@ public class EncodingUtils
* @param buffer
* @param data
*/
- public static void writeLongstr(DataOutputStream buffer, byte[] data) throws IOException
+ public static void writeLongstr(ByteBuffer buffer, byte[] data)
{
if (data != null)
{
writeUnsignedInteger(buffer, data.length);
- buffer.write(data);
+ buffer.put(data);
}
else
{
@@ -609,14 +608,14 @@ public class EncodingUtils
}
}
- public static void writeTimestamp(DataOutputStream buffer, long timestamp) throws IOException
+ public static void writeTimestamp(ByteBuffer buffer, long timestamp)
{
writeLong(buffer, timestamp);
}
- public static boolean[] readBooleans(DataInputStream buffer) throws IOException
+ public static boolean[] readBooleans(ByteBuffer buffer)
{
- final byte packedValue = buffer.readByte();
+ final byte packedValue = buffer.get();
if (packedValue == 0)
{
return ALL_FALSE_ARRAY;
@@ -641,9 +640,9 @@ public class EncodingUtils
return result;
}
- public static FieldTable readFieldTable(DataInputStream buffer) throws AMQFrameDecodingException, IOException
+ public static FieldTable readFieldTable(ByteBuffer buffer) throws AMQFrameDecodingException
{
- long length = ((long)(buffer.readInt())) & 0xFFFFFFFFL;
+ long length = buffer.getUnsignedInt();
if (length == 0)
{
return null;
@@ -654,21 +653,21 @@ public class EncodingUtils
}
}
- public static Content readContent(DataInputStream buffer) throws AMQFrameDecodingException
+ public static Content readContent(ByteBuffer buffer) throws AMQFrameDecodingException
{
// TODO: New Content class required for AMQP 0-9.
return null;
}
- public static AMQShortString readAMQShortString(DataInputStream buffer) throws IOException
+ public static AMQShortString readAMQShortString(ByteBuffer buffer)
{
return AMQShortString.readFromBuffer(buffer);
}
- public static String readShortString(DataInputStream buffer) throws IOException
+ public static String readShortString(ByteBuffer buffer)
{
- short length = (short) (((short)buffer.readByte()) & 0xFF);
+ short length = buffer.getUnsigned();
if (length == 0)
{
return null;
@@ -681,7 +680,7 @@ public class EncodingUtils
// this approach here is valid since we know that all the chars are
// ASCII (0-127)
byte[] stringBytes = new byte[length];
- buffer.read(stringBytes, 0, length);
+ buffer.get(stringBytes, 0, length);
char[] stringChars = new char[length];
for (int i = 0; i < stringChars.length; i++)
{
@@ -692,9 +691,9 @@ public class EncodingUtils
}
}
- public static String readLongString(DataInputStream buffer) throws IOException
+ public static String readLongString(ByteBuffer buffer)
{
- long length = ((long)(buffer.readInt())) & 0xFFFFFFFFL;
+ long length = buffer.getUnsignedInt();
if (length == 0)
{
return "";
@@ -707,7 +706,7 @@ public class EncodingUtils
// this approach here is valid since we know that all the chars are
// ASCII (0-127)
byte[] stringBytes = new byte[(int) length];
- buffer.read(stringBytes, 0, (int) length);
+ buffer.get(stringBytes, 0, (int) length);
char[] stringChars = new char[(int) length];
for (int i = 0; i < stringChars.length; i++)
{
@@ -718,9 +717,9 @@ public class EncodingUtils
}
}
- public static byte[] readLongstr(DataInputStream buffer) throws IOException
+ public static byte[] readLongstr(ByteBuffer buffer)
{
- long length = ((long)(buffer.readInt())) & 0xFFFFFFFFL;
+ long length = buffer.getUnsignedInt();
if (length == 0)
{
return null;
@@ -728,17 +727,17 @@ public class EncodingUtils
else
{
byte[] result = new byte[(int) length];
- buffer.read(result);
+ buffer.get(result);
return result;
}
}
- public static long readTimestamp(DataInputStream buffer) throws IOException
+ public static long readTimestamp(ByteBuffer buffer)
{
// Discard msb from AMQ timestamp
// buffer.getUnsignedInt();
- return buffer.readLong();
+ return buffer.getLong();
}
static byte[] hexToByteArray(String id)
@@ -818,14 +817,14 @@ public class EncodingUtils
// AMQP_BOOLEAN_PROPERTY_PREFIX
- public static void writeBoolean(DataOutputStream buffer, Boolean aBoolean) throws IOException
+ public static void writeBoolean(ByteBuffer buffer, Boolean aBoolean)
{
- buffer.write(aBoolean ? 1 : 0);
+ buffer.put((byte) (aBoolean ? 1 : 0));
}
- public static boolean readBoolean(DataInputStream buffer) throws IOException
+ public static boolean readBoolean(ByteBuffer buffer)
{
- byte packedValue = buffer.readByte();
+ byte packedValue = buffer.get();
return (packedValue == 1);
}
@@ -836,14 +835,14 @@ public class EncodingUtils
}
// AMQP_BYTE_PROPERTY_PREFIX
- public static void writeByte(DataOutputStream buffer, Byte aByte) throws IOException
+ public static void writeByte(ByteBuffer buffer, Byte aByte)
{
- buffer.writeByte(aByte);
+ buffer.put(aByte);
}
- public static byte readByte(DataInputStream buffer) throws IOException
+ public static byte readByte(ByteBuffer buffer)
{
- return buffer.readByte();
+ return buffer.get();
}
public static int encodedByteLength()
@@ -852,14 +851,14 @@ public class EncodingUtils
}
// AMQP_SHORT_PROPERTY_PREFIX
- public static void writeShort(DataOutputStream buffer, Short aShort) throws IOException
+ public static void writeShort(ByteBuffer buffer, Short aShort)
{
- buffer.writeShort(aShort);
+ buffer.putShort(aShort);
}
- public static short readShort(DataInputStream buffer) throws IOException
+ public static short readShort(ByteBuffer buffer)
{
- return buffer.readShort();
+ return buffer.getShort();
}
public static int encodedShortLength()
@@ -868,14 +867,14 @@ public class EncodingUtils
}
// INTEGER_PROPERTY_PREFIX
- public static void writeInteger(DataOutputStream buffer, Integer aInteger) throws IOException
+ public static void writeInteger(ByteBuffer buffer, Integer aInteger)
{
- buffer.writeInt(aInteger);
+ buffer.putInt(aInteger);
}
- public static int readInteger(DataInputStream buffer) throws IOException
+ public static int readInteger(ByteBuffer buffer)
{
- return buffer.readInt();
+ return buffer.getInt();
}
public static int encodedIntegerLength()
@@ -884,14 +883,14 @@ public class EncodingUtils
}
// AMQP_LONG_PROPERTY_PREFIX
- public static void writeLong(DataOutputStream buffer, Long aLong) throws IOException
+ public static void writeLong(ByteBuffer buffer, Long aLong)
{
- buffer.writeLong(aLong);
+ buffer.putLong(aLong);
}
- public static long readLong(DataInputStream buffer) throws IOException
+ public static long readLong(ByteBuffer buffer)
{
- return buffer.readLong();
+ return buffer.getLong();
}
public static int encodedLongLength()
@@ -900,14 +899,14 @@ public class EncodingUtils
}
// Float_PROPERTY_PREFIX
- public static void writeFloat(DataOutputStream buffer, Float aFloat) throws IOException
+ public static void writeFloat(ByteBuffer buffer, Float aFloat)
{
- buffer.writeFloat(aFloat);
+ buffer.putFloat(aFloat);
}
- public static float readFloat(DataInputStream buffer) throws IOException
+ public static float readFloat(ByteBuffer buffer)
{
- return buffer.readFloat();
+ return buffer.getFloat();
}
public static int encodedFloatLength()
@@ -916,14 +915,14 @@ public class EncodingUtils
}
// Double_PROPERTY_PREFIX
- public static void writeDouble(DataOutputStream buffer, Double aDouble) throws IOException
+ public static void writeDouble(ByteBuffer buffer, Double aDouble)
{
- buffer.writeDouble(aDouble);
+ buffer.putDouble(aDouble);
}
- public static double readDouble(DataInputStream buffer) throws IOException
+ public static double readDouble(ByteBuffer buffer)
{
- return buffer.readDouble();
+ return buffer.getDouble();
}
public static int encodedDoubleLength()
@@ -931,9 +930,9 @@ public class EncodingUtils
return 8;
}
- public static byte[] readBytes(DataInputStream buffer) throws IOException
+ public static byte[] readBytes(ByteBuffer buffer)
{
- long length = ((long)(buffer.readInt())) & 0xFFFFFFFFL;
+ long length = buffer.getUnsignedInt();
if (length == 0)
{
return null;
@@ -941,19 +940,19 @@ public class EncodingUtils
else
{
byte[] dataBytes = new byte[(int)length];
- buffer.read(dataBytes, 0, (int) length);
+ buffer.get(dataBytes, 0, (int)length);
return dataBytes;
}
}
- public static void writeBytes(DataOutputStream buffer, byte[] data) throws IOException
+ public static void writeBytes(ByteBuffer buffer, byte[] data)
{
if (data != null)
{
// TODO: check length fits in an unsigned byte
writeUnsignedInteger(buffer, (long)data.length);
- buffer.write(data);
+ buffer.put(data);
}
else
{
@@ -969,35 +968,35 @@ public class EncodingUtils
return encodedByteLength();
}
- public static char readChar(DataInputStream buffer) throws IOException
+ public static char readChar(ByteBuffer buffer)
{
// This is valid as we know that the Character is ASCII 0..127
- return (char) buffer.read();
+ return (char) buffer.get();
}
- public static void writeChar(DataOutputStream buffer, char character) throws IOException
+ public static void writeChar(ByteBuffer buffer, char character)
{
// This is valid as we know that the Character is ASCII 0..127
writeByte(buffer, (byte) character);
}
- public static long readLongAsShortString(DataInputStream buffer) throws IOException
+ public static long readLongAsShortString(ByteBuffer buffer)
{
- short length = (short) buffer.readUnsignedByte();
+ short length = buffer.getUnsigned();
short pos = 0;
if (length == 0)
{
return 0L;
}
- byte digit = buffer.readByte();
+ byte digit = buffer.get();
boolean isNegative;
long result = 0;
if (digit == (byte) '-')
{
isNegative = true;
pos++;
- digit = buffer.readByte();
+ digit = buffer.get();
}
else
{
@@ -1010,7 +1009,7 @@ public class EncodingUtils
while (pos < length)
{
pos++;
- digit = buffer.readByte();
+ digit = buffer.get();
result = (result << 3) + (result << 1);
result += digit - (byte) '0';
}
@@ -1018,15 +1017,15 @@ public class EncodingUtils
return result;
}
- public static long readUnsignedInteger(DataInputStream buffer) throws IOException
+ public static long readUnsignedInteger(ByteBuffer buffer)
{
- long l = 0xFF & buffer.readByte();
+ long l = 0xFF & buffer.get();
l <<= 8;
- l = l | (0xFF & buffer.readByte());
+ l = l | (0xFF & buffer.get());
l <<= 8;
- l = l | (0xFF & buffer.readByte());
+ l = l | (0xFF & buffer.get());
l <<= 8;
- l = l | (0xFF & buffer.readByte());
+ l = l | (0xFF & buffer.get());
return l;
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java b/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java
index 721c821bab..22205d49f8 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/FieldTable.java
@@ -20,16 +20,12 @@
*/
package org.apache.qpid.framing;
+import org.apache.mina.common.ByteBuffer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.qpid.AMQPInvalidClassException;
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.Enumeration;
@@ -47,8 +43,8 @@ public class FieldTable
private static final String STRICT_AMQP = "STRICT_AMQP";
private final boolean _strictAMQP = Boolean.valueOf(System.getProperty(STRICT_AMQP, "false"));
- private byte[] _encodedForm;
- private LinkedHashMap<AMQShortString, AMQTypedValue> _properties = null;
+ private ByteBuffer _encodedForm;
+ private LinkedHashMap<AMQShortString, AMQTypedValue> _properties;
private long _encodedSize;
private static final int INITIAL_HASHMAP_CAPACITY = 16;
private static final int INITIAL_ENCODED_FORM_SIZE = 256;
@@ -56,6 +52,9 @@ public class FieldTable
public FieldTable()
{
super();
+ // _encodedForm = ByteBuffer.allocate(INITIAL_ENCODED_FORM_SIZE);
+ // _encodedForm.setAutoExpand(true);
+ // _encodedForm.limit(0);
}
/**
@@ -64,12 +63,16 @@ public class FieldTable
* @param buffer the buffer from which to read data. The length byte must be read already
* @param length the length of the field table. Must be > 0.
*/
- public FieldTable(DataInputStream buffer, long length) throws IOException
+ public FieldTable(ByteBuffer buffer, long length)
{
this();
- _encodedForm = new byte[(int) length];
- buffer.read(_encodedForm);
+ ByteBuffer encodedForm = buffer.slice();
+ encodedForm.limit((int) length);
+ _encodedForm = ByteBuffer.allocate((int)length);
+ _encodedForm.put(encodedForm);
+ _encodedForm.flip();
_encodedSize = length;
+ buffer.skip((int) length);
}
public AMQTypedValue getProperty(AMQShortString string)
@@ -105,19 +108,13 @@ public class FieldTable
{
try
{
- setFromBuffer();
+ setFromBuffer(_encodedForm, _encodedSize);
}
catch (AMQFrameDecodingException e)
{
_logger.error("Error decoding FieldTable in deferred decoding mode ", e);
throw new IllegalArgumentException(e);
}
- catch (IOException e)
- {
- _logger.error("Unexpected IO exception decoding field table");
- throw new IllegalArgumentException(e);
-
- }
}
private AMQTypedValue setProperty(AMQShortString key, AMQTypedValue val)
@@ -769,7 +766,7 @@ public class FieldTable
// ************************* Byte Buffer Processing
- public void writeToBuffer(DataOutputStream buffer) throws IOException
+ public void writeToBuffer(ByteBuffer buffer)
{
final boolean trace = _logger.isDebugEnabled();
@@ -789,21 +786,17 @@ public class FieldTable
public byte[] getDataAsBytes()
{
- if(_encodedForm == null)
- {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try
- {
- putDataInBuffer(new DataOutputStream(baos));
- return baos.toByteArray();
- }
- catch (IOException e)
- {
- throw new IllegalArgumentException("IO Exception should never be thrown here");
- }
+ final int encodedSize = (int) getEncodedSize();
+ final ByteBuffer buffer = ByteBuffer.allocate(encodedSize); // FIXME XXX: Is cast a problem?
- }
- return _encodedForm.clone();
+ putDataInBuffer(buffer);
+
+ final byte[] result = new byte[encodedSize];
+ buffer.flip();
+ buffer.get(result);
+ buffer.release();
+
+ return result;
}
public long getEncodedSize()
@@ -933,8 +926,15 @@ public class FieldTable
public Iterator<Map.Entry<AMQShortString, AMQTypedValue>> iterator()
{
- initMapIfNecessary();
- return _properties.entrySet().iterator();
+ if(_encodedForm != null)
+ {
+ return new FieldTableIterator(_encodedForm.duplicate().rewind(),(int)_encodedSize);
+ }
+ else
+ {
+ initMapIfNecessary();
+ return _properties.entrySet().iterator();
+ }
}
public Object get(String key)
@@ -1002,12 +1002,26 @@ public class FieldTable
return _properties.keySet();
}
- private void putDataInBuffer(DataOutputStream buffer) throws IOException
+ private void putDataInBuffer(ByteBuffer buffer)
{
if (_encodedForm != null)
{
- buffer.write(_encodedForm);
+ if(buffer.isDirect() || buffer.isReadOnly())
+ {
+ ByteBuffer encodedForm = _encodedForm.duplicate();
+
+ if (encodedForm.position() != 0)
+ {
+ encodedForm.flip();
+ }
+
+ buffer.put(encodedForm);
+ }
+ else
+ {
+ buffer.put(_encodedForm.array(),_encodedForm.arrayOffset(),(int)_encodedSize);
+ }
}
else if (_properties != null)
{
@@ -1021,27 +1035,41 @@ public class FieldTable
final Map.Entry<AMQShortString, AMQTypedValue> me = it.next();
try
{
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Writing Property:" + me.getKey() + " Type:" + me.getValue().getType() + " Value:"
+ + me.getValue().getValue());
+ _logger.debug("Buffer Position:" + buffer.position() + " Remaining:" + buffer.remaining());
+ }
+
// Write the actual parameter name
EncodingUtils.writeShortStringBytes(buffer, me.getKey());
me.getValue().writeToBuffer(buffer);
}
catch (Exception e)
{
+ if (_logger.isDebugEnabled())
+ {
+ _logger.debug("Exception thrown:" + e);
+ _logger.debug("Writing Property:" + me.getKey() + " Type:" + me.getValue().getType() + " Value:"
+ + me.getValue().getValue());
+ _logger.debug("Buffer Position:" + buffer.position() + " Remaining:" + buffer.remaining());
+ }
+
throw new RuntimeException(e);
}
}
}
}
- private void setFromBuffer() throws AMQFrameDecodingException, IOException
+ private void setFromBuffer(ByteBuffer buffer, long length) throws AMQFrameDecodingException
{
- final ByteArrayInputStream in = new ByteArrayInputStream(_encodedForm);
- DataInputStream buffer = new DataInputStream(in);
final boolean trace = _logger.isDebugEnabled();
- if (_encodedSize > 0)
+ if (length > 0)
{
+ final int expectedRemaining = buffer.remaining() - (int) length;
_properties = new LinkedHashMap<AMQShortString, AMQTypedValue>(INITIAL_HASHMAP_CAPACITY);
@@ -1049,16 +1077,121 @@ public class FieldTable
{
final AMQShortString key = EncodingUtils.readAMQShortString(buffer);
+
+ _logger.debug("FieldTable::PropFieldTable(buffer," + length + "): Read key '" + key);
+
AMQTypedValue value = AMQTypedValue.readFromBuffer(buffer);
+
+ if (trace)
+ {
+ _logger.debug("FieldTable::PropFieldTable(buffer," + length + "): Read type '" + value.getType()
+ + "', key '" + key + "', value '" + value.getValue() + "'");
+ }
+
_properties.put(key, value);
}
- while (in.available() > 0);
+ while (buffer.remaining() > expectedRemaining);
+
+ }
+
+ _encodedSize = length;
+
+ if (trace)
+ {
+ _logger.debug("FieldTable::FieldTable(buffer," + length + "): Done.");
+ }
+ }
+
+ private static final class FieldTableEntry implements Map.Entry<AMQShortString, AMQTypedValue>
+ {
+ private final AMQTypedValue _value;
+ private final AMQShortString _key;
+
+ public FieldTableEntry(final AMQShortString key, final AMQTypedValue value)
+ {
+ _key = key;
+ _value = value;
+ }
+
+ public AMQShortString getKey()
+ {
+ return _key;
+ }
+
+ public AMQTypedValue getValue()
+ {
+ return _value;
+ }
+
+ public AMQTypedValue setValue(final AMQTypedValue value)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean equals(Object o)
+ {
+ if(o instanceof FieldTableEntry)
+ {
+ FieldTableEntry other = (FieldTableEntry) o;
+ return (_key == null ? other._key == null : _key.equals(other._key))
+ && (_value == null ? other._value == null : _value.equals(other._value));
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ public int hashCode()
+ {
+ return (getKey()==null ? 0 : getKey().hashCode())
+ ^ (getValue()==null ? 0 : getValue().hashCode());
+ }
+
+ }
+
+
+ private static final class FieldTableIterator implements Iterator<Map.Entry<AMQShortString, AMQTypedValue>>
+ {
+ private final ByteBuffer _buffer;
+ private int _expectedRemaining;
+
+ public FieldTableIterator(ByteBuffer buffer, int length)
+ {
+ _buffer = buffer;
+ _expectedRemaining = buffer.remaining() - length;
+ }
+
+ public boolean hasNext()
+ {
+ return (_buffer.remaining() > _expectedRemaining);
}
+ public Map.Entry<AMQShortString, AMQTypedValue> next()
+ {
+ if(hasNext())
+ {
+ final AMQShortString key = EncodingUtils.readAMQShortString(_buffer);
+ AMQTypedValue value = AMQTypedValue.readFromBuffer(_buffer);
+ return new FieldTableEntry(key, value);
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public void remove()
+ {
+ throw new UnsupportedOperationException();
+ }
}
+
+
+
public int hashCode()
{
initMapIfNecessary();
diff --git a/java/common/src/main/java/org/apache/qpid/framing/FieldTableFactory.java b/java/common/src/main/java/org/apache/qpid/framing/FieldTableFactory.java
index 438a46f28b..e9d75137ef 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/FieldTableFactory.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/FieldTableFactory.java
@@ -20,8 +20,7 @@
*/
package org.apache.qpid.framing;
-import java.io.DataInputStream;
-import java.io.IOException;
+import org.apache.mina.common.ByteBuffer;
public class FieldTableFactory
{
@@ -30,7 +29,7 @@ public class FieldTableFactory
return new FieldTable();
}
- public static FieldTable newFieldTable(DataInputStream byteBuffer, long length) throws AMQFrameDecodingException, IOException
+ public static FieldTable newFieldTable(ByteBuffer byteBuffer, long length) throws AMQFrameDecodingException
{
return new FieldTable(byteBuffer, length);
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBody.java b/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBody.java
index a6ce721a50..18ab05ffa1 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBody.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBody.java
@@ -20,10 +20,7 @@
*/
package org.apache.qpid.framing;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-
+import org.apache.mina.common.ByteBuffer;
import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
import org.apache.qpid.AMQException;
@@ -37,12 +34,12 @@ public class HeartbeatBody implements AMQBody
}
- public HeartbeatBody(DataInputStream buffer, long size) throws IOException
+ public HeartbeatBody(ByteBuffer buffer, long size)
{
if(size > 0)
{
//allow other implementations to have a payload, but ignore it:
- buffer.skip(size);
+ buffer.skip((int) size);
}
}
@@ -56,7 +53,7 @@ public class HeartbeatBody implements AMQBody
return 0;//heartbeats we generate have no payload
}
- public void writePayload(DataOutputStream buffer)
+ public void writePayload(ByteBuffer buffer)
{
}
@@ -66,12 +63,12 @@ public class HeartbeatBody implements AMQBody
session.heartbeatBodyReceived(channelId, this);
}
- protected void populateFromBuffer(DataInputStream buffer, long size) throws AMQFrameDecodingException, IOException
+ protected void populateFromBuffer(ByteBuffer buffer, long size) throws AMQFrameDecodingException
{
if(size > 0)
{
//allow other implementations to have a payload, but ignore it:
- buffer.skip(size);
+ buffer.skip((int) size);
}
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBodyFactory.java b/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBodyFactory.java
index dfc49c6167..c7ada708dc 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBodyFactory.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/HeartbeatBodyFactory.java
@@ -20,11 +20,11 @@
*/
package org.apache.qpid.framing;
-import java.io.DataInputStream;
+import org.apache.mina.common.ByteBuffer;
public class HeartbeatBodyFactory implements BodyFactory
{
- public AMQBody createBody(DataInputStream in, long bodySize) throws AMQFrameDecodingException
+ public AMQBody createBody(ByteBuffer in, long bodySize) throws AMQFrameDecodingException
{
return new HeartbeatBody();
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/ProtocolInitiation.java b/java/common/src/main/java/org/apache/qpid/framing/ProtocolInitiation.java
index 8c018316f0..fb3dd89717 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/ProtocolInitiation.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/ProtocolInitiation.java
@@ -22,10 +22,6 @@ package org.apache.qpid.framing;
import org.apache.qpid.AMQException;
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
-
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.Arrays;
@@ -66,30 +62,35 @@ public class ProtocolInitiation extends AMQDataBlock implements EncodableAMQData
pv.equals(ProtocolVersion.v0_91) ? 1 : pv.getMinorVersion());
}
- public ProtocolInitiation(DataInputStream in) throws IOException
+ public ProtocolInitiation(ByteBuffer in)
{
_protocolHeader = new byte[4];
- in.read(_protocolHeader);
+ in.get(_protocolHeader);
- _protocolClass = in.readByte();
- _protocolInstance = in.readByte();
- _protocolMajor = in.readByte();
- _protocolMinor = in.readByte();
+ _protocolClass = in.get();
+ _protocolInstance = in.get();
+ _protocolMajor = in.get();
+ _protocolMinor = in.get();
}
+ public void writePayload(org.apache.mina.common.ByteBuffer buffer)
+ {
+ writePayload(buffer.buf());
+ }
+
public long getSize()
{
return 4 + 1 + 1 + 1 + 1;
}
- public void writePayload(DataOutputStream buffer) throws IOException
+ public void writePayload(ByteBuffer buffer)
{
- buffer.write(_protocolHeader);
- buffer.write(_protocolClass);
- buffer.write(_protocolInstance);
- buffer.write(_protocolMajor);
- buffer.write(_protocolMinor);
+ buffer.put(_protocolHeader);
+ buffer.put(_protocolClass);
+ buffer.put(_protocolInstance);
+ buffer.put(_protocolMajor);
+ buffer.put(_protocolMinor);
}
public boolean equals(Object o)
@@ -143,9 +144,9 @@ public class ProtocolInitiation extends AMQDataBlock implements EncodableAMQData
* @return true if we have enough data to decode the PI frame fully, false if more
* data is required
*/
- public boolean decodable(DataInputStream in) throws IOException
+ public boolean decodable(ByteBuffer in)
{
- return (in.available() >= 8);
+ return (in.remaining() >= 8);
}
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/SmallCompositeAMQDataBlock.java b/java/common/src/main/java/org/apache/qpid/framing/SmallCompositeAMQDataBlock.java
index d2925d13a8..bd763599b0 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/SmallCompositeAMQDataBlock.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/SmallCompositeAMQDataBlock.java
@@ -21,8 +21,7 @@
package org.apache.qpid.framing;
-import java.io.DataOutputStream;
-import java.io.IOException;
+import org.apache.mina.common.ByteBuffer;
public class SmallCompositeAMQDataBlock extends AMQDataBlock implements EncodableAMQDataBlock
{
@@ -69,7 +68,7 @@ public class SmallCompositeAMQDataBlock extends AMQDataBlock implements Encodabl
return frameSize;
}
- public void writePayload(DataOutputStream buffer) throws IOException
+ public void writePayload(ByteBuffer buffer)
{
if (_firstFrame != null)
{
diff --git a/java/common/src/main/java/org/apache/qpid/framing/VersionSpecificRegistry.java b/java/common/src/main/java/org/apache/qpid/framing/VersionSpecificRegistry.java
index ed9136f7c9..76c154581d 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/VersionSpecificRegistry.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/VersionSpecificRegistry.java
@@ -20,8 +20,7 @@
*/
package org.apache.qpid.framing;
-import java.io.DataInputStream;
-import java.io.IOException;
+import org.apache.mina.common.ByteBuffer;
import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter;
@@ -145,7 +144,7 @@ public class VersionSpecificRegistry
}
- public AMQMethodBody get(short classID, short methodID, DataInputStream in, long size) throws AMQFrameDecodingException, IOException
+ public AMQMethodBody get(short classID, short methodID, ByteBuffer in, long size) throws AMQFrameDecodingException
{
AMQMethodBodyInstanceFactory bodyFactory;
try
diff --git a/java/common/src/main/java/org/apache/qpid/framing/abstraction/ContentChunk.java b/java/common/src/main/java/org/apache/qpid/framing/abstraction/ContentChunk.java
index 470b7b05e3..0695349f76 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/abstraction/ContentChunk.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/abstraction/ContentChunk.java
@@ -21,10 +21,12 @@
package org.apache.qpid.framing.abstraction;
+import org.apache.mina.common.ByteBuffer;
+
public interface ContentChunk
{
int getSize();
- byte[] getData();
+ ByteBuffer getData();
void reduceToFit();
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/abstraction/ProtocolVersionMethodConverter.java b/java/common/src/main/java/org/apache/qpid/framing/abstraction/ProtocolVersionMethodConverter.java
index d1e53d6907..7544d9b7e7 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/abstraction/ProtocolVersionMethodConverter.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/abstraction/ProtocolVersionMethodConverter.java
@@ -23,6 +23,8 @@ package org.apache.qpid.framing.abstraction;
import org.apache.qpid.framing.AMQBody;
+import java.nio.ByteBuffer;
+
public interface ProtocolVersionMethodConverter extends MessagePublishInfoConverter
{
AMQBody convertToBody(ContentChunk contentBody);
@@ -30,5 +32,5 @@ public interface ProtocolVersionMethodConverter extends MessagePublishInfoConver
void configure();
- AMQBody convertToBody(byte[] input);
+ AMQBody convertToBody(ByteBuffer buf);
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/MethodConverter_0_9.java b/java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/MethodConverter_0_9.java
index 90a730d6f7..1c4a29b106 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/MethodConverter_0_9.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/MethodConverter_0_9.java
@@ -21,13 +21,16 @@
package org.apache.qpid.framing.amqp_0_9;
+import org.apache.mina.common.ByteBuffer;
+
import org.apache.qpid.framing.abstraction.AbstractMethodConverter;
import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter;
import org.apache.qpid.framing.abstraction.ContentChunk;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.framing.abstraction.MessagePublishInfoImpl;
import org.apache.qpid.framing.*;
-
+import org.apache.qpid.framing.amqp_0_9.*;
+import org.apache.qpid.framing.amqp_0_9.BasicPublishBodyImpl;
public class MethodConverter_0_9 extends AbstractMethodConverter implements ProtocolVersionMethodConverter
{
@@ -69,9 +72,9 @@ public class MethodConverter_0_9 extends AbstractMethodConverter implements Prot
}
- public AMQBody convertToBody(byte[] data)
+ public AMQBody convertToBody(java.nio.ByteBuffer buf)
{
- return new ContentBody(data);
+ return new ContentBody(ByteBuffer.wrap(buf));
}
public MessagePublishInfo convertToInfo(AMQMethodBody methodBody)
@@ -113,9 +116,9 @@ public class MethodConverter_0_9 extends AbstractMethodConverter implements Prot
return _contentBodyChunk.getSize();
}
- public byte[] getData()
+ public ByteBuffer getData()
{
- return _contentBodyChunk._payload;
+ return _contentBodyChunk.payload;
}
public void reduceToFit()
diff --git a/java/common/src/main/java/org/apache/qpid/framing/amqp_0_91/MethodConverter_0_91.java b/java/common/src/main/java/org/apache/qpid/framing/amqp_0_91/MethodConverter_0_91.java
index 3b0cc3cebc..6e330574bc 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/amqp_0_91/MethodConverter_0_91.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/amqp_0_91/MethodConverter_0_91.java
@@ -21,6 +21,8 @@
package org.apache.qpid.framing.amqp_0_91;
+import org.apache.mina.common.ByteBuffer;
+
import org.apache.qpid.framing.abstraction.AbstractMethodConverter;
import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter;
import org.apache.qpid.framing.abstraction.ContentChunk;
@@ -68,9 +70,9 @@ public class MethodConverter_0_91 extends AbstractMethodConverter implements Pro
}
- public AMQBody convertToBody(byte[] data)
+ public AMQBody convertToBody(java.nio.ByteBuffer buf)
{
- return new ContentBody(data);
+ return new ContentBody(ByteBuffer.wrap(buf));
}
public MessagePublishInfo convertToInfo(AMQMethodBody methodBody)
@@ -112,9 +114,9 @@ public class MethodConverter_0_91 extends AbstractMethodConverter implements Pro
return _contentBodyChunk.getSize();
}
- public byte[] getData()
+ public ByteBuffer getData()
{
- return _contentBodyChunk._payload;
+ return _contentBodyChunk.payload;
}
public void reduceToFit()
diff --git a/java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/MethodConverter_8_0.java b/java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/MethodConverter_8_0.java
index e6d0482f0d..c87820b9b2 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/MethodConverter_8_0.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/MethodConverter_8_0.java
@@ -26,8 +26,11 @@ import org.apache.qpid.framing.abstraction.ContentChunk;
import org.apache.qpid.framing.abstraction.MessagePublishInfo;
import org.apache.qpid.framing.abstraction.AbstractMethodConverter;
import org.apache.qpid.framing.abstraction.MessagePublishInfoImpl;
+import org.apache.qpid.framing.amqp_8_0.BasicPublishBodyImpl;
import org.apache.qpid.framing.*;
+import org.apache.mina.common.ByteBuffer;
+
public class MethodConverter_8_0 extends AbstractMethodConverter implements ProtocolVersionMethodConverter
{
private int _basicPublishClassId;
@@ -57,9 +60,9 @@ public class MethodConverter_8_0 extends AbstractMethodConverter implements Prot
return contentBodyChunk.getSize();
}
- public byte[] getData()
+ public ByteBuffer getData()
{
- return contentBodyChunk._payload;
+ return contentBodyChunk.payload;
}
public void reduceToFit()
@@ -78,9 +81,9 @@ public class MethodConverter_8_0 extends AbstractMethodConverter implements Prot
}
- public AMQBody convertToBody(byte[] data)
+ public AMQBody convertToBody(java.nio.ByteBuffer buf)
{
- return new ContentBody(data);
+ return new ContentBody(ByteBuffer.wrap(buf));
}
public MessagePublishInfo convertToInfo(AMQMethodBody methodBody)
diff --git a/java/common/src/main/java/org/apache/qpid/pool/Job.java b/java/common/src/main/java/org/apache/qpid/pool/Job.java
new file mode 100644
index 0000000000..82b600de88
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/pool/Job.java
@@ -0,0 +1,253 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.pool;
+
+import java.util.concurrent.ConcurrentLinkedQueue;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.RejectedExecutionException;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A Job is a continuation that batches together other continuations, specifically {@link Event}s, into one continuation.
+ * The {@link Event}s themselves provide methods to process themselves, so processing a job simply consists of sequentially
+ * processing all of its aggregated events.
+ *
+ * The constructor accepts a maximum number of events for the job, and only runs up to that maximum number when
+ * processing the job, but the add method does not enforce this maximum. In other words, not all the enqueued events
+ * may be processed in each run of the job, several runs may be required to clear the queue.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Aggregate many coninuations together into a single continuation.
+ * <tr><td> Sequentially process aggregated continuations. <td> {@link Event}
+ * <tr><td> Provide running and completion status of the aggregate continuation.
+ * <tr><td> Execute a terminal continuation upon job completion. <td> {@link JobCompletionHandler}
+ * </table>
+ *
+ * @todo Could make Job implement Runnable, FutureTask, or a custom Continuation interface, to clarify its status as a
+ * continuation. Job is a continuation that aggregates other continuations and as such is a usefull re-usable
+ * piece of code. There may be other palces than the mina filter chain where continuation batching is used within
+ * qpid, so abstracting this out could provide a usefull building block. This also opens the way to different
+ * kinds of job with a common interface, e.g. parallel or sequential jobs etc.
+ *
+ * @todo For better re-usability could make the completion handler optional. Only run it when one is set.
+ */
+public class Job implements ReadWriteRunnable
+{
+
+ /** Defines the maximum number of events that will be batched into a single job. */
+ public static final int MAX_JOB_EVENTS = Integer.getInteger("amqj.server.read_write_pool.max_events", 10);
+
+ /** The maximum number of events to process per run of the job. More events than this may be queued in the job. */
+ private final int _maxEvents;
+
+ /** Holds the queue of events that make up the job. */
+ private final java.util.Queue<Runnable> _eventQueue = new ConcurrentLinkedQueue<Runnable>();
+
+ /** Holds a status flag, that indicates when the job is actively running. */
+ private final AtomicBoolean _active = new AtomicBoolean();
+
+ private final boolean _readJob;
+
+ private ReferenceCountingExecutorService _poolReference;
+
+ private final static Logger _logger = LoggerFactory.getLogger(Job.class);
+
+ public Job(ReferenceCountingExecutorService poolReference, int maxEvents, boolean readJob)
+ {
+ _poolReference = poolReference;
+ _maxEvents = maxEvents;
+ _readJob = readJob;
+ }
+
+ /**
+ * Enqueus a continuation for sequential processing by this job.
+ *
+ * @param evt The continuation to enqueue.
+ */
+ public void add(Runnable evt)
+ {
+ _eventQueue.add(evt);
+ }
+
+ /**
+ * Sequentially processes, up to the maximum number per job, the aggregated continuations in enqueued in this job.
+ */
+ boolean processAll()
+ {
+ // limit the number of events processed in one run
+ int i = _maxEvents;
+ while( --i != 0 )
+ {
+ Runnable e = _eventQueue.poll();
+ if (e == null)
+ {
+ return true;
+ }
+ else
+ {
+ e.run();
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Tests if there are no more enqueued continuations to process.
+ *
+ * @return <tt>true</tt> if there are no enqueued continuations in this job, <tt>false</tt> otherwise.
+ */
+ public boolean isComplete()
+ {
+ return _eventQueue.peek() == null;
+ }
+
+ /**
+ * Marks this job as active if it is inactive. This method is thread safe.
+ *
+ * @return <tt>true</tt> if this job was inactive and has now been marked as active, <tt>false</tt> otherwise.
+ */
+ public boolean activate()
+ {
+ return _active.compareAndSet(false, true);
+ }
+
+ /**
+ * Marks this job as inactive. This method is thread safe.
+ */
+ public void deactivate()
+ {
+ _active.set(false);
+ }
+
+ /**
+ * Processes a batch of aggregated continuations, marks this job as inactive and call the terminal continuation.
+ */
+ public void run()
+ {
+ if(processAll())
+ {
+ deactivate();
+ completed();
+ }
+ else
+ {
+ notCompleted();
+ }
+ }
+
+ public boolean isRead()
+ {
+ return _readJob;
+ }
+
+ /**
+ * Adds an {@link Event} to a {@link Job}, triggering the execution of the job if it is not already running.
+ *
+ * @param job The job.
+ * @param event The event to hand off asynchronously.
+ */
+ public static void fireAsynchEvent(ExecutorService pool, Job job, Runnable event)
+ {
+
+ job.add(event);
+
+
+ if(pool == null)
+ {
+ return;
+ }
+
+ // rather than perform additional checks on pool to check that it hasn't shutdown.
+ // catch the RejectedExecutionException that will result from executing on a shutdown pool
+ if (job.activate())
+ {
+ try
+ {
+ pool.execute(job);
+ }
+ catch(RejectedExecutionException e)
+ {
+ _logger.warn("Thread pool shutdown while tasks still outstanding");
+ }
+ }
+
+ }
+
+ /**
+ * Implements a terminal continuation for the {@link Job} for this filter. Whenever the Job completes its processing
+ * of a batch of events this is called. This method simply re-activates the job, if it has more events to process.
+ *
+ * @param session The Mina session to work in.
+ * @param job The job that completed.
+ */
+ public void completed()
+ {
+ if (!isComplete())
+ {
+ final ExecutorService pool = _poolReference.getPool();
+
+ if(pool == null)
+ {
+ return;
+ }
+
+
+ // ritchiem : 2006-12-13 Do we need to perform the additional checks here?
+ // Can the pool be shutdown at this point?
+ if (activate())
+ {
+ try
+ {
+ pool.execute(this);
+ }
+ catch(RejectedExecutionException e)
+ {
+ _logger.warn("Thread pool shutdown while tasks still outstanding");
+ }
+
+ }
+ }
+ }
+
+ public void notCompleted()
+ {
+ final ExecutorService pool = _poolReference.getPool();
+
+ if(pool == null)
+ {
+ return;
+ }
+
+ try
+ {
+ pool.execute(this);
+ }
+ catch(RejectedExecutionException e)
+ {
+ _logger.warn("Thread pool shutdown while tasks still outstanding");
+ }
+ }
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/protocol/AMQConstant.java b/java/common/src/main/java/org/apache/qpid/protocol/AMQConstant.java
index 14d1befaf1..f0f2652ce3 100644
--- a/java/common/src/main/java/org/apache/qpid/protocol/AMQConstant.java
+++ b/java/common/src/main/java/org/apache/qpid/protocol/AMQConstant.java
@@ -80,7 +80,7 @@ public final class AMQConstant
/**
* An operator intervened to close the connection for some reason. The client may retry at some later date.
*/
- public static final AMQConstant CONNECTION_FORCED = new AMQConstant(320, "connection forced", true);
+ public static final AMQConstant CONTEXT_IN_USE = new AMQConstant(320, "context in use", true);
/** The client tried to work with an unknown virtual host or cluster. */
public static final AMQConstant INVALID_PATH = new AMQConstant(402, "invalid path", true);
@@ -104,7 +104,7 @@ public final class AMQConstant
public static final AMQConstant REQUEST_TIMEOUT = new AMQConstant(408, "Request Timeout", true);
- public static final AMQConstant ARGUMENT_INVALID = new AMQConstant(409, "argument invalid", true);
+ public static final AMQConstant INVALID_ARGUMENT = new AMQConstant(409, "argument invalid", true);
/**
* The client sent a malformed frame that the server could not decode. This strongly implies a programming error
@@ -153,7 +153,10 @@ public final class AMQConstant
public static final AMQConstant FRAME_MIN_SIZE = new AMQConstant(4096, "frame min size", true);
- public static final AMQConstant INVALID_ARGUMENT = new AMQConstant(542, "invalid argument", true);
+ /**
+ * The server does not support the protocol version
+ */
+ public static final AMQConstant UNSUPPORTED_BROKER_PROTOCOL_ERROR = new AMQConstant(542, "broker unsupported protocol", true);
/**
* The client imp does not support the protocol version
*/
diff --git a/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngine.java b/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngine.java
index fd651a2b66..31953ea6ab 100644
--- a/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngine.java
+++ b/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngine.java
@@ -21,11 +21,10 @@
package org.apache.qpid.protocol;
import java.net.SocketAddress;
-import java.nio.ByteBuffer;
+import org.apache.qpid.framing.AMQDataBlock;
+import org.apache.qpid.transport.NetworkDriver;
import org.apache.qpid.transport.Receiver;
-import org.apache.qpid.transport.Sender;
-import org.apache.qpid.transport.network.NetworkConnection;
/**
* A ProtocolEngine is a Receiver for java.nio.ByteBuffers. It takes the data passed to it in the received
@@ -33,6 +32,9 @@ import org.apache.qpid.transport.network.NetworkConnection;
*/
public interface ProtocolEngine extends Receiver<java.nio.ByteBuffer>
{
+ // Sets the network driver providing data for this ProtocolEngine
+ void setNetworkDriver (NetworkDriver driver);
+
// Returns the remote address of the NetworkDriver
SocketAddress getRemoteAddress();
@@ -56,6 +58,4 @@ public interface ProtocolEngine extends Receiver<java.nio.ByteBuffer>
void readerIdle();
- public void setNetworkConnection(NetworkConnection network, Sender<ByteBuffer> sender);
-
} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngineFactory.java b/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngineFactory.java
index 7378edff0c..9df84eef90 100644
--- a/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngineFactory.java
+++ b/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngineFactory.java
@@ -20,12 +20,12 @@
*/
package org.apache.qpid.protocol;
-import org.apache.qpid.transport.network.NetworkConnection;
+import org.apache.qpid.transport.NetworkDriver;
public interface ProtocolEngineFactory
{
// Returns a new instance of a ProtocolEngine
- ProtocolEngine newProtocolEngine();
+ ProtocolEngine newProtocolEngine(NetworkDriver networkDriver);
} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/protocol/ServerProtocolEngine.java b/java/common/src/main/java/org/apache/qpid/security/AMQPCallbackHandler.java
index e8362f79f0..a3dad9acdc 100644
--- a/java/common/src/main/java/org/apache/qpid/protocol/ServerProtocolEngine.java
+++ b/java/common/src/main/java/org/apache/qpid/security/AMQPCallbackHandler.java
@@ -7,9 +7,9 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
@@ -18,12 +18,11 @@
* under the License.
*
*/
-package org.apache.qpid.protocol;
+package org.apache.qpid.security;
+
+import javax.security.auth.callback.CallbackHandler;
-public interface ServerProtocolEngine extends ProtocolEngine
+public interface AMQPCallbackHandler extends CallbackHandler
{
- /**
- * Gets the connection ID associated with this ProtocolEngine
- */
- long getConnectionId();
+ void initialise(String username,String password);
}
diff --git a/java/common/src/main/java/org/apache/qpid/security/UsernamePasswordCallbackHandler.java b/java/common/src/main/java/org/apache/qpid/security/UsernamePasswordCallbackHandler.java
new file mode 100644
index 0000000000..89a63abeab
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/security/UsernamePasswordCallbackHandler.java
@@ -0,0 +1,60 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.security;
+
+import java.io.IOException;
+
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.NameCallback;
+import javax.security.auth.callback.PasswordCallback;
+import javax.security.auth.callback.UnsupportedCallbackException;
+
+public class UsernamePasswordCallbackHandler implements AMQPCallbackHandler
+{
+ private String _username;
+ private String _password;
+
+ public void initialise(String username,String password)
+ {
+ _username = username;
+ _password = password;
+ }
+
+ public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
+ {
+ for (int i = 0; i < callbacks.length; i++)
+ {
+ Callback cb = callbacks[i];
+ if (cb instanceof NameCallback)
+ {
+ ((NameCallback)cb).setName(_username);
+ }
+ else if (cb instanceof PasswordCallback)
+ {
+ ((PasswordCallback)cb).setPassword((_password).toCharArray());
+ }
+ else
+ {
+ throw new UnsupportedCallbackException(cb);
+ }
+ }
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java b/java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java
index 01f13408b0..702746b3da 100644
--- a/java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java
+++ b/java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java
@@ -20,17 +20,18 @@
*/
package org.apache.qpid.ssl;
+import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import javax.net.ssl.KeyManager;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
-import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
-import org.apache.qpid.transport.network.security.ssl.QpidClientX509KeyManager;
import org.apache.qpid.transport.network.security.ssl.SSLUtil;
/**
@@ -38,92 +39,157 @@ import org.apache.qpid.transport.network.security.ssl.SSLUtil;
* before this will work.
*
*/
-public class SSLContextFactory
-{
- public static final String JAVA_KEY_STORE_CODE = "JKS";
- public static final String TRANSPORT_LAYER_SECURITY_CODE = "TLS";
- public static final String KEY_STORE_CERTIFICATE_TYPE = "SunX509";
-
- private SSLContextFactory()
+public class SSLContextFactory {
+
+ /**
+ * Path to the Java keystore file
+ */
+ private String _keyStorePath;
+
+ /**
+ * Password for the keystore
+ */
+ private String _keyStorePassword;
+
+ /**
+ * Cert type to use in keystore
+ */
+ private String _keyStoreCertType;
+
+ /**
+ * Path to the Java truststore file
+ */
+ private String _trustStorePath;
+
+ /**
+ * Password for the truststore
+ */
+ private String _trustStorePassword;
+
+ /**
+ * Cert type to use in truststore
+ */
+ private String _trustStoreCertType;
+
+ private KeyManager customKeyManager;
+
+ public SSLContextFactory(String trustStorePath, String trustStorePassword,
+ String trustStoreCertType)
{
- //no instances
+ this(trustStorePath,trustStorePassword,trustStoreCertType,
+ trustStorePath,trustStorePassword,trustStoreCertType);
}
- public static SSLContext buildServerContext(final String keyStorePath,
- final String keyStorePassword, final String keyStoreCertType)
- throws GeneralSecurityException, IOException
- {
- return buildContext(null, null, null, keyStorePath, keyStorePassword,
- keyStoreCertType, null);
- }
+ /**
+ * Create a factory instance
+ * @param keystorePath path to the Java keystore file
+ * @param keystorePassword password for the Java keystore
+ * @param certType certificate type
+ */
+ public SSLContextFactory(String trustStorePath, String trustStorePassword, String trustStoreCertType,
+ String keyStorePath, String keyStorePassword, String keyStoreCertType)
+ {
- public static SSLContext buildClientContext(final String trustStorePath,
- final String trustStorePassword, final String trustStoreCertType,
- final String keyStorePath, final String keyStorePassword,
- final String keyStoreCertType, final String certAlias)
- throws GeneralSecurityException, IOException
- {
- return buildContext(trustStorePath, trustStorePassword,
- trustStoreCertType, keyStorePath, keyStorePassword,
- keyStoreCertType, certAlias);
- }
-
- private static SSLContext buildContext(final String trustStorePath,
- final String trustStorePassword, final String trustStoreCertType,
- final String keyStorePath, final String keyStorePassword,
- final String keyStoreCertType, final String certAlias)
- throws GeneralSecurityException, IOException
+ _trustStorePath = trustStorePath;
+ _trustStorePassword = trustStorePassword;
+
+ if (_trustStorePassword != null && _trustStorePassword.equals("none"))
+ {
+ _trustStorePassword = null;
+ }
+ _trustStoreCertType = trustStoreCertType;
+
+ _keyStorePath = keyStorePath;
+ _keyStorePassword = keyStorePassword;
+
+ if (_keyStorePassword != null && _keyStorePassword.equals("none"))
+ {
+ _keyStorePassword = null;
+ }
+ _keyStoreCertType = keyStoreCertType;
+
+ if (_trustStorePath == null) {
+ throw new IllegalArgumentException("A TrustStore path or KeyStore path must be specified");
+ }
+ if (_trustStoreCertType == null) {
+ throw new IllegalArgumentException("Cert type must be specified");
+ }
+ }
+
+ public SSLContextFactory(String trustStorePath, String trustStorePassword, String trustStoreCertType,
+ KeyManager customKeyManager)
{
- // Initialize the SSLContext to work with our key managers.
- final SSLContext sslContext = SSLContext
- .getInstance(TRANSPORT_LAYER_SECURITY_CODE);
- final TrustManager[] trustManagers;
- final KeyManager[] keyManagers;
-
- if (trustStorePath != null)
+ _trustStorePath = trustStorePath;
+ _trustStorePassword = trustStorePassword;
+
+ if (_trustStorePassword != null && _trustStorePassword.equals("none"))
{
- final KeyStore ts = SSLUtil.getInitializedKeyStore(trustStorePath,
- trustStorePassword);
- final TrustManagerFactory tmf = TrustManagerFactory
- .getInstance(trustStoreCertType);
- tmf.init(ts);
-
- trustManagers = tmf.getTrustManagers();
+ _trustStorePassword = null;
}
- else
- {
- trustManagers = null;
+ _trustStoreCertType = trustStoreCertType;
+
+ if (_trustStorePath == null) {
+ throw new IllegalArgumentException("A TrustStore path or KeyStore path must be specified");
+ }
+ if (_trustStoreCertType == null) {
+ throw new IllegalArgumentException("Cert type must be specified");
}
+
+ this.customKeyManager = customKeyManager;
+ }
+
+
+ /**
+ * Builds a SSLContext appropriate for use with a server
+ * @return SSLContext
+ * @throws GeneralSecurityException
+ * @throws IOException
+ */
- if (keyStorePath != null)
+ public SSLContext buildServerContext() throws GeneralSecurityException, IOException
+ {
+ KeyStore ts = SSLUtil.getInitializedKeyStore(_trustStorePath,_trustStorePassword);
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(_trustStoreCertType);
+ tmf.init(ts);
+
+ // Initialize the SSLContext to work with our key managers.
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+
+ if (customKeyManager != null)
{
- if (certAlias != null)
- {
- keyManagers = new KeyManager[] { new QpidClientX509KeyManager(
- certAlias, keyStorePath, keyStorePassword,
- keyStoreCertType) };
- }
- else
- {
- final KeyStore ks = SSLUtil.getInitializedKeyStore(
- keyStorePath, keyStorePassword);
-
- char[] keyStoreCharPassword = keyStorePassword == null ? null : keyStorePassword.toCharArray();
- // Set up key manager factory to use our key store
- final KeyManagerFactory kmf = KeyManagerFactory
- .getInstance(keyStoreCertType);
- kmf.init(ks, keyStoreCharPassword);
- keyManagers = kmf.getKeyManagers();
- }
+ sslContext.init(new KeyManager[]{customKeyManager},
+ tmf.getTrustManagers(), null);
+
}
else
{
- keyManagers = null;
- }
+ // Create keystore
+ KeyStore ks = SSLUtil.getInitializedKeyStore(_keyStorePath,_keyStorePassword);
+ // Set up key manager factory to use our key store
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(_keyStoreCertType);
+ kmf.init(ks, _keyStorePassword.toCharArray());
- sslContext.init(keyManagers, trustManagers, null);
-
- return sslContext;
- }
+ sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
+ }
+
+ return sslContext;
+ }
+
+ /**
+ * Creates a SSLContext factory appropriate for use with a client
+ * @return SSLContext
+ * @throws GeneralSecurityException
+ * @throws IOException
+ */
+ public SSLContext buildClientContext() throws GeneralSecurityException, IOException
+ {
+ KeyStore ks = SSLUtil.getInitializedKeyStore(_trustStorePath,_trustStorePassword);
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(_trustStoreCertType);
+ tmf.init(ks);
+ SSLContext context = SSLContext.getInstance("TLS");
+ context.init(null, tmf.getTrustManagers(), null);
+ return context;
+ }
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/thread/QpidThreadExecutor.java b/java/common/src/main/java/org/apache/qpid/thread/QpidThreadExecutor.java
index 30010a2d89..38f60c04fe 100644
--- a/java/common/src/main/java/org/apache/qpid/thread/QpidThreadExecutor.java
+++ b/java/common/src/main/java/org/apache/qpid/thread/QpidThreadExecutor.java
@@ -23,7 +23,7 @@ package org.apache.qpid.thread;
import org.apache.qpid.thread.Threading;
-import java.util.concurrent.Executor;
+import edu.emory.mathcs.backport.java.util.concurrent.Executor;
public class QpidThreadExecutor implements Executor
{
diff --git a/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java b/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java
index 9bdad6b00e..0d9f8c0b28 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java
@@ -20,20 +20,28 @@
*/
package org.apache.qpid.transport;
+import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.GSSManager;
+import org.ietf.jgss.GSSName;
+import org.ietf.jgss.Oid;
+
+import org.apache.qpid.security.UsernamePasswordCallbackHandler;
import static org.apache.qpid.transport.Connection.State.OPEN;
import static org.apache.qpid.transport.Connection.State.RESUMING;
+import org.apache.qpid.transport.util.Logger;
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import javax.security.sasl.SaslClient;
-import javax.security.sasl.SaslException;
-
-import org.apache.qpid.transport.util.Logger;
-
/**
* ClientDelegate
@@ -44,13 +52,31 @@ public class ClientDelegate extends ConnectionDelegate
{
private static final Logger log = Logger.get(ClientDelegate.class);
+ private static final String KRB5_OID_STR = "1.2.840.113554.1.2.2";
+ protected static final Oid KRB5_OID;
+ static
+ {
+ Oid oid;
+ try
+ {
+ oid = new Oid(KRB5_OID_STR);
+ }
+ catch (GSSException ignore)
+ {
+ oid = null;
+ }
- protected final ConnectionSettings _conSettings;
+ KRB5_OID = oid;
+ }
+
+ private List<String> clientMechs;
+ private ConnectionSettings conSettings;
public ClientDelegate(ConnectionSettings settings)
{
- this._conSettings = settings;
+ this.conSettings = settings;
+ this.clientMechs = Arrays.asList(settings.getSaslMechs().split(" "));
}
public void init(Connection conn, ProtocolHeader hdr)
@@ -66,9 +92,9 @@ public class ClientDelegate extends ConnectionDelegate
{
Map<String,Object> clientProperties = new HashMap<String,Object>();
- if(this._conSettings.getClientProperties() != null)
+ if(this.conSettings.getClientProperties() != null)
{
- clientProperties.putAll(_conSettings.getClientProperties());
+ clientProperties.putAll(this.conSettings.getClientProperties());
}
clientProperties.put("qpid.session_flow", 1);
@@ -83,12 +109,41 @@ public class ClientDelegate extends ConnectionDelegate
(clientProperties, null, null, conn.getLocale());
return;
}
+
+ List<String> choosenMechs = new ArrayList<String>();
+ for (String mech:clientMechs)
+ {
+ if (brokerMechs.contains(mech))
+ {
+ choosenMechs.add(mech);
+ }
+ }
+
+ if (choosenMechs.size() == 0)
+ {
+ conn.exception(new ConnectionException("The following SASL mechanisms " +
+ clientMechs.toString() +
+ " specified by the client are not supported by the broker"));
+ return;
+ }
+
+ String[] mechs = new String[choosenMechs.size()];
+ choosenMechs.toArray(mechs);
+
conn.setServerProperties(start.getServerProperties());
try
{
- final SaslClient sc = createSaslClient(brokerMechs);
-
+ Map<String,Object> saslProps = new HashMap<String,Object>();
+ if (conSettings.isUseSASLEncryption())
+ {
+ saslProps.put(Sasl.QOP, "auth-conf");
+ }
+ UsernamePasswordCallbackHandler handler =
+ new UsernamePasswordCallbackHandler();
+ handler.initialise(conSettings.getUsername(), conSettings.getPassword());
+ SaslClient sc = Sasl.createSaslClient
+ (mechs, null, conSettings.getSaslProtocol(), conSettings.getSaslServerName(), saslProps, handler);
conn.setSaslClient(sc);
byte[] response = sc.hasInitialResponse() ?
@@ -97,22 +152,12 @@ public class ClientDelegate extends ConnectionDelegate
(clientProperties, sc.getMechanismName(), response,
conn.getLocale());
}
- catch (ConnectionException ce)
- {
- conn.exception(ce);
- }
catch (SaslException e)
{
conn.exception(e);
}
}
-
- protected SaslClient createSaslClient(List<Object> brokerMechs) throws ConnectionException, SaslException
- {
- throw new UnsupportedOperationException();
- }
-
@Override
public void connectionSecure(Connection conn, ConnectionSecure secure)
{
@@ -131,7 +176,7 @@ public class ClientDelegate extends ConnectionDelegate
@Override
public void connectionTune(Connection conn, ConnectionTune tune)
{
- int hb_interval = calculateHeartbeatInterval(_conSettings.getHeartbeatInterval(),
+ int hb_interval = calculateHeartbeatInterval(conSettings.getHeartbeatInterval(),
tune.getHeartbeatMin(),
tune.getHeartbeatMax()
);
@@ -146,12 +191,32 @@ public class ClientDelegate extends ConnectionDelegate
//(or that forced by protocol limitations [0xFFFF])
conn.setChannelMax(channelMax == 0 ? Connection.MAX_CHANNEL_MAX : channelMax);
- conn.connectionOpen(_conSettings.getVhost(), null, Option.INSIST);
+ conn.connectionOpen(conSettings.getVhost(), null, Option.INSIST);
}
@Override
public void connectionOpenOk(Connection conn, ConnectionOpenOk ok)
{
+ SaslClient sc = conn.getSaslClient();
+ if (sc != null)
+ {
+ if (sc.getMechanismName().equals("GSSAPI"))
+ {
+ String id = getKerberosUser();
+ if (id != null)
+ {
+ conn.setUserID(id);
+ }
+ }
+ else if (sc.getMechanismName().equals("EXTERNAL"))
+ {
+ if (conn.getSecurityLayer() != null)
+ {
+ conn.setUserID(conn.getSecurityLayer().getUserID());
+ }
+ }
+ }
+
if (conn.isConnectionResuming())
{
conn.setState(RESUMING);
@@ -182,7 +247,7 @@ public class ClientDelegate extends ConnectionDelegate
int i = heartbeat;
if (i == 0)
{
- log.info("Idle timeout is 0 sec. Heartbeats are disabled.");
+ log.warn("Idle timeout is zero. Heartbeats are disabled");
return 0; // heartbeats are disabled.
}
else if (i >= min && i <= max)
@@ -191,8 +256,8 @@ public class ClientDelegate extends ConnectionDelegate
}
else
{
- log.info("The broker does not support the configured connection idle timeout of %s sec," +
- " using the brokers max supported value of %s sec instead.", i,max);
+ log.warn("Ignoring the idle timeout %s set by the connection," +
+ " using the brokers max value %s", i,max);
return max;
}
}
@@ -221,7 +286,35 @@ public class ClientDelegate extends ConnectionDelegate
}
+ private String getKerberosUser()
+ {
+ log.debug("Obtaining userID from kerberos");
+ String service = conSettings.getSaslProtocol() + "@" + conSettings.getSaslServerName();
+ GSSManager manager = GSSManager.getInstance();
+
+ try
+ {
+ GSSName acceptorName = manager.createName(service,
+ GSSName.NT_HOSTBASED_SERVICE, KRB5_OID);
+
+ GSSContext secCtx = manager.createContext(acceptorName,
+ KRB5_OID,
+ null,
+ GSSContext.INDEFINITE_LIFETIME);
+ secCtx.initSecContext(new byte[0], 0, 1);
+ if (secCtx.getSrcName() != null)
+ {
+ return secCtx.getSrcName().toString();
+ }
+ }
+ catch (GSSException e)
+ {
+ log.warn("Unable to retrieve userID from Kerberos due to error",e);
+ }
+
+ return null;
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/Connection.java b/java/common/src/main/java/org/apache/qpid/transport/Connection.java
index 1c521244d0..e5e10c0e07 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/Connection.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/Connection.java
@@ -25,29 +25,21 @@ import static org.apache.qpid.transport.Connection.State.CLOSING;
import static org.apache.qpid.transport.Connection.State.NEW;
import static org.apache.qpid.transport.Connection.State.OPEN;
import static org.apache.qpid.transport.Connection.State.OPENING;
+import static org.apache.qpid.transport.Connection.State.RESUMING;
-import java.nio.ByteBuffer;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
import javax.security.sasl.SaslClient;
import javax.security.sasl.SaslServer;
-import org.apache.qpid.framing.ProtocolVersion;
-import org.apache.qpid.transport.network.Assembler;
-import org.apache.qpid.transport.network.Disassembler;
-import org.apache.qpid.transport.network.InputHandler;
-import org.apache.qpid.transport.network.NetworkConnection;
-import org.apache.qpid.transport.network.OutgoingNetworkTransport;
-import org.apache.qpid.transport.network.Transport;
import org.apache.qpid.transport.network.security.SecurityLayer;
-import org.apache.qpid.transport.network.security.SecurityLayerFactory;
import org.apache.qpid.transport.util.Logger;
import org.apache.qpid.transport.util.Waiter;
import org.apache.qpid.util.Strings;
@@ -73,7 +65,6 @@ public class Connection extends ConnectionInvoker
public static final int MAX_CHANNEL_MAX = 0xFFFF;
public static final int MIN_USABLE_CHANNEL_NUM = 0;
-
public enum State { NEW, CLOSED, OPENING, OPEN, CLOSING, CLOSE_RCVD, RESUMING }
static class DefaultConnectionListener implements ConnectionListener
@@ -121,14 +112,17 @@ public class Connection extends ConnectionInvoker
private SaslServer saslServer;
private SaslClient saslClient;
private int idleTimeout = 0;
+ private String _authorizationID;
private Map<String,Object> _serverProperties;
private String userID;
private ConnectionSettings conSettings;
private SecurityLayer securityLayer;
private String _clientId;
-
+
+ private static final AtomicLong idGenerator = new AtomicLong(0);
+ private final long _connectionId = idGenerator.incrementAndGet();
private final AtomicBoolean connectionLost = new AtomicBoolean(false);
-
+
public Connection() {}
public void setConnectionDelegate(ConnectionDelegate delegate)
@@ -239,24 +233,14 @@ public class Connection extends ConnectionInvoker
conSettings = settings;
state = OPENING;
userID = settings.getUsername();
-
- securityLayer = SecurityLayerFactory.newInstance(getConnectionSettings());
-
- OutgoingNetworkTransport transport = Transport.getOutgoingTransportInstance(ProtocolVersion.v0_10);
- Receiver<ByteBuffer> secureReceiver = securityLayer.receiver(new InputHandler(new Assembler(this)));
- if(secureReceiver instanceof ConnectionListener)
- {
- addConnectionListener((ConnectionListener)secureReceiver);
- }
-
- NetworkConnection network = transport.connect(settings, secureReceiver, null);
- final Sender<ByteBuffer> secureSender = securityLayer.sender(network.getSender());
- if(secureSender instanceof ConnectionListener)
- {
- addConnectionListener((ConnectionListener)secureSender);
- }
- sender = new Disassembler(secureSender, settings.getMaxFrameSize());
-
+ delegate = new ClientDelegate(settings);
+
+ TransportBuilder transport = new TransportBuilder();
+ transport.init(this);
+ this.sender = transport.buildSenderPipe();
+ transport.buildReceiverPipe(this);
+ this.securityLayer = transport.getSecurityLayer();
+
send(new ProtocolHeader(1, 0, 10));
Waiter w = new Waiter(lock, timeout);
@@ -337,31 +321,23 @@ public class Connection extends ConnectionInvoker
Waiter w = new Waiter(lock, timeout);
while (w.hasTime() && state != OPEN && error == null)
{
- w.await();
+ w.await();
}
-
+
if (state != OPEN)
{
throw new ConnectionException("Timed out waiting for connection to be ready. Current state is :" + state);
}
-
+
Session ssn = _sessionFactory.newSession(this, name, expiry);
- registerSession(ssn);
+ sessions.put(name, ssn);
map(ssn);
ssn.attach();
return ssn;
}
}
- public void registerSession(Session ssn)
- {
- synchronized (lock)
- {
- sessions.put(ssn.getName(),ssn);
- }
- }
-
- public void removeSession(Session ssn)
+ void removeSession(Session ssn)
{
synchronized (lock)
{
@@ -376,6 +352,11 @@ public class Connection extends ConnectionInvoker
_sessionFactory = sessionFactory;
}
+ public long getConnectionId()
+ {
+ return _connectionId;
+ }
+
public ConnectionDelegate getConnectionDelegate()
{
return delegate;
@@ -424,7 +405,7 @@ public class Connection extends ConnectionInvoker
else
{
throw new ProtocolViolationException(
- "Received frames for an already detached session", null);
+ "Received frames for an already dettached session", null);
}
}
@@ -473,7 +454,7 @@ public class Connection extends ConnectionInvoker
}
}
- public Session getSession(int channel)
+ protected Session getSession(int channel)
{
synchronized (lock)
{
@@ -487,10 +468,18 @@ public class Connection extends ConnectionInvoker
{
for (Session ssn : sessions.values())
{
- map(ssn);
- ssn.resume();
+ if (ssn.isTransacted())
+ {
+ removeSession(ssn);
+ ssn.setState(Session.State.CLOSED);
+ }
+ else
+ {
+ map(ssn);
+ ssn.attach();
+ ssn.resume();
+ }
}
-
setState(OPEN);
}
}
@@ -577,12 +566,12 @@ public class Connection extends ConnectionInvoker
{
close(ConnectionCloseCode.NORMAL, null);
}
-
+
public void mgmtClose()
{
close(ConnectionCloseCode.CONNECTION_FORCED, "The connection was closed using the broker's management interface.");
}
-
+
public void close(ConnectionCloseCode replyCode, String replyText, Option ... _options)
{
synchronized (lock)
@@ -656,6 +645,16 @@ public class Connection extends ConnectionInvoker
return idleTimeout;
}
+ public void setAuthorizationID(String authorizationID)
+ {
+ _authorizationID = authorizationID;
+ }
+
+ public String getAuthorizationID()
+ {
+ return _authorizationID;
+ }
+
public String getUserID()
{
return userID;
@@ -685,24 +684,15 @@ public class Connection extends ConnectionInvoker
{
return conSettings;
}
-
+
public SecurityLayer getSecurityLayer()
{
return securityLayer;
}
-
+
public boolean isConnectionResuming()
{
return connectionLost.get();
}
- protected Collection<Session> getChannels()
- {
- return channels.values();
- }
-
- public boolean hasSessionWithName(final String name)
- {
- return sessions.containsKey(new Binary(name.getBytes()));
- }
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/ConnectionDelegate.java b/java/common/src/main/java/org/apache/qpid/transport/ConnectionDelegate.java
index 393301659d..88dd2d6afa 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/ConnectionDelegate.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/ConnectionDelegate.java
@@ -85,7 +85,7 @@ public abstract class ConnectionDelegate
@Override public void sessionDetach(Connection conn, SessionDetach dtc)
{
Session ssn = conn.getSession(dtc.getChannel());
- ssn.sessionDetached(dtc.getName(), ssn.getDetachCode() == null? SessionDetachCode.NORMAL: ssn.getDetachCode());
+ ssn.sessionDetached(dtc.getName(), SessionDetachCode.NORMAL);
conn.unmap(ssn);
ssn.closed();
}
@@ -95,7 +95,6 @@ public abstract class ConnectionDelegate
Session ssn = conn.getSession(dtc.getChannel());
if (ssn != null)
{
- ssn.setDetachCode(dtc.getCode());
conn.unmap(ssn);
ssn.closed();
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java b/java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java
index 37a8e594c0..08678b213b 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/ConnectionSettings.java
@@ -30,8 +30,6 @@ import java.util.Map;
*/
public class ConnectionSettings
{
- public static final String WILDCARD_ADDRESS = "*";
-
String protocol = "tcp";
String host = "localhost";
String vhost;
@@ -58,7 +56,7 @@ public class ConnectionSettings
boolean verifyHostname;
// SASL props
- String saslMechs = System.getProperty("qpid.sasl_mechs", null);
+ String saslMechs = System.getProperty("qpid.sasl_mechs", "PLAIN");
String saslProtocol = System.getProperty("qpid.sasl_protocol", "AMQP");
String saslServerName = System.getProperty("qpid.sasl_server_name", "localhost");
boolean useSASLEncryption;
diff --git a/java/common/src/main/java/org/apache/qpid/transport/NetworkDriver.java b/java/common/src/main/java/org/apache/qpid/transport/NetworkDriver.java
new file mode 100644
index 0000000000..86af97bf7e
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/NetworkDriver.java
@@ -0,0 +1,63 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.transport;
+
+import java.net.BindException;
+import java.net.InetAddress;
+import java.net.SocketAddress;
+
+import org.apache.qpid.protocol.ProtocolEngine;
+import org.apache.qpid.protocol.ProtocolEngineFactory;
+import org.apache.qpid.ssl.SSLContextFactory;
+
+public interface NetworkDriver extends Sender<java.nio.ByteBuffer>
+{
+ // Creates a NetworkDriver which attempts to connect to destination on port and attaches the ProtocolEngine to
+ // it using the SSLContextFactory if provided
+ void open(int port, InetAddress destination, ProtocolEngine engine,
+ NetworkDriverConfiguration config, SSLContextFactory sslFactory)
+ throws OpenException;
+
+ // listens for incoming connections on the specified ports and address and creates a new NetworkDriver which
+ // processes incoming connections with ProtocolEngines and SSLEngines created from the factories
+ // (in the case of an SSLContextFactory, if provided)
+ void bind (int port, InetAddress[] addresses, ProtocolEngineFactory protocolFactory,
+ NetworkDriverConfiguration config, SSLContextFactory sslFactory) throws BindException;
+
+ // Returns the remote address of the underlying socket
+ SocketAddress getRemoteAddress();
+
+ // Returns the local address of the underlying socket
+ SocketAddress getLocalAddress();
+
+ /**
+ * The length of time after which the ProtocolEngines readIdle() method should be called if no data has been
+ * read in seconds
+ */
+ void setMaxReadIdle(int idleTime);
+
+ /**
+ * The length of time after which the ProtocolEngines writeIdle() method should be called if no data has been
+ * written in seconds
+ */
+ void setMaxWriteIdle(int idleTime);
+
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/transport/NetworkTransportConfiguration.java b/java/common/src/main/java/org/apache/qpid/transport/NetworkDriverConfiguration.java
index 8d3f7a779a..c38afe5dd5 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/NetworkTransportConfiguration.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/NetworkDriverConfiguration.java
@@ -25,22 +25,20 @@ package org.apache.qpid.transport;
* buffer sizes and set particular options on the socket. NetworkDrivers should honour the values returned
* from here if the underlying implementation supports them.
*/
-public interface NetworkTransportConfiguration
+public interface NetworkDriverConfiguration
{
// Taken from Socket
+ Boolean getKeepAlive();
+ Boolean getOOBInline();
+ Boolean getReuseAddress();
+ Integer getSoLinger(); // null means off
+ Integer getSoTimeout();
Boolean getTcpNoDelay();
+ Integer getTrafficClass();
// The amount of memory in bytes to allocate to the incoming buffer
Integer getReceiveBufferSize();
// The amount of memory in bytes to allocate to the outgoing buffer
- Integer getSendBufferSize();
-
- Integer getPort();
-
- String getHost();
-
- String getTransport();
-
- Integer getConnectorProcessors();
-}
+ Integer getSendBufferSize();
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java b/java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java
index 82fa6ca473..f21df251da 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java
@@ -75,7 +75,10 @@ public class ServerDelegate extends ConnectionDelegate
if (mechanism == null || mechanism.length() == 0)
{
- tuneAuthorizedConnection(conn);
+ conn.connectionTune
+ (getChannelMax(),
+ org.apache.qpid.transport.network.ConnectionBinding.MAX_FRAME_SIZE,
+ 0, getHeartbeatMax());
return;
}
@@ -94,7 +97,8 @@ public class ServerDelegate extends ConnectionDelegate
}
catch (SaslException e)
{
- connectionAuthFailed(conn, e);
+ conn.exception(e);
+ conn.connectionClose(ConnectionCloseCode.CONNECTION_FORCED, e.getMessage());
}
}
@@ -105,52 +109,33 @@ public class ServerDelegate extends ConnectionDelegate
return ss;
}
- protected void secure(final SaslServer ss, final Connection conn, final byte[] response)
+ private void secure(Connection conn, byte[] response)
{
+ SaslServer ss = conn.getSaslServer();
try
{
byte[] challenge = ss.evaluateResponse(response);
if (ss.isComplete())
{
ss.dispose();
- tuneAuthorizedConnection(conn);
+ conn.connectionTune
+ (getChannelMax(),
+ org.apache.qpid.transport.network.ConnectionBinding.MAX_FRAME_SIZE,
+ 0, getHeartbeatMax());
+ conn.setAuthorizationID(ss.getAuthorizationID());
}
else
{
- connectionAuthContinue(conn, challenge);
+ conn.connectionSecure(challenge);
}
}
catch (SaslException e)
{
- connectionAuthFailed(conn, e);
+ conn.exception(e);
+ conn.connectionClose(ConnectionCloseCode.CONNECTION_FORCED, e.getMessage());
}
}
- protected void connectionAuthFailed(final Connection conn, Exception e)
- {
- conn.exception(e);
- conn.connectionClose(ConnectionCloseCode.CONNECTION_FORCED, e.getMessage());
- }
-
- protected void connectionAuthContinue(final Connection conn, byte[] challenge)
- {
- conn.connectionSecure(challenge);
- }
-
- protected void tuneAuthorizedConnection(final Connection conn)
- {
- conn.connectionTune
- (getChannelMax(),
- org.apache.qpid.transport.network.ConnectionBinding.MAX_FRAME_SIZE,
- 0, getHeartbeatMax());
- }
-
- protected void secure(final Connection conn, final byte[] response)
- {
- final SaslServer ss = conn.getSaslServer();
- secure(ss, conn, response);
- }
-
protected int getHeartbeatMax()
{
return 0xFFFF;
@@ -170,7 +155,22 @@ public class ServerDelegate extends ConnectionDelegate
@Override
public void connectionTuneOk(Connection conn, ConnectionTuneOk ok)
{
+ int okChannelMax = ok.getChannelMax();
+
+ if (okChannelMax > getChannelMax())
+ {
+ _logger.error("Connection '" + conn.getConnectionId() + "' being severed, " +
+ "client connectionTuneOk returned a channelMax (" + okChannelMax +
+ ") above the servers offered limit (" + getChannelMax() +")");
+ //Due to the error we must forcefully close the connection without negotiation
+ conn.getSender().close();
+ return;
+ }
+
+ //0 means no implied limit, except available server resources
+ //(or that forced by protocol limitations [0xFFFF])
+ conn.setChannelMax(okChannelMax == 0 ? Connection.MAX_CHANNEL_MAX : okChannelMax);
}
@Override
@@ -200,11 +200,4 @@ public class ServerDelegate extends ConnectionDelegate
ssn.sessionAttached(atc.getName());
ssn.setState(Session.State.OPEN);
}
-
- protected void setConnectionTuneOkChannelMax(final Connection conn, final int okChannelMax)
- {
- //0 means no implied limit, except available server resources
- //(or that forced by protocol limitations [0xFFFF])
- conn.setChannelMax(okChannelMax == 0 ? Connection.MAX_CHANNEL_MAX : okChannelMax);
- }
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/Session.java b/java/common/src/main/java/org/apache/qpid/transport/Session.java
index 0de558d152..214d4534c1 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/Session.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/Session.java
@@ -30,8 +30,6 @@ import static org.apache.qpid.transport.Session.State.DETACHED;
import static org.apache.qpid.transport.Session.State.NEW;
import static org.apache.qpid.transport.Session.State.OPEN;
import static org.apache.qpid.transport.Session.State.RESUMING;
-
-import org.apache.qpid.configuration.ClientProperties;
import org.apache.qpid.transport.network.Frame;
import static org.apache.qpid.transport.util.Functions.mod;
import org.apache.qpid.transport.util.Logger;
@@ -44,9 +42,7 @@ import static org.apache.qpid.util.Serial.max;
import static org.apache.qpid.util.Strings.toUTF8;
import java.nio.ByteBuffer;
-import java.util.Arrays;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
@@ -59,6 +55,7 @@ import java.util.concurrent.TimeUnit;
public class Session extends SessionInvoker
{
+
private static final Logger log = Logger.get(Session.class);
public enum State { NEW, DETACHED, RESUMING, OPEN, CLOSING, CLOSED }
@@ -92,9 +89,7 @@ public class Session extends SessionInvoker
private int channel;
private SessionDelegate delegate;
private SessionListener listener = new DefaultSessionListener();
- private final long timeout = Long.getLong(ClientProperties.QPID_SYNC_OP_TIMEOUT,
- Long.getLong(ClientProperties.AMQJ_DEFAULT_SYNCWRITE_TIMEOUT,
- ClientProperties.DEFAULT_SYNC_OPERATION_TIMEOUT));
+ private long timeout = 60000;
private boolean autoSync = false;
private boolean incomingInit;
@@ -122,9 +117,7 @@ public class Session extends SessionInvoker
private Thread resumer = null;
private boolean transacted = false;
- private SessionDetachCode detachCode;
- private final Object stateLock = new Object();
-
+
protected Session(Connection connection, Binary name, long expiry)
{
this(connection, new SessionDelegate(), name, expiry);
@@ -259,8 +252,6 @@ public class Session extends SessionInvoker
{
synchronized (commands)
{
- attach();
-
for (int i = maxComplete + 1; lt(i, commandsOut); i++)
{
Method m = commands[mod(i, commands.length)];
@@ -271,48 +262,16 @@ public class Session extends SessionInvoker
}
else if (m instanceof MessageTransfer)
{
- MessageTransfer xfr = (MessageTransfer)m;
-
- if (xfr.getHeader() != null)
- {
- if (xfr.getHeader().get(DeliveryProperties.class) != null)
- {
- xfr.getHeader().get(DeliveryProperties.class).setRedelivered(true);
- }
- else
- {
- Struct[] structs = xfr.getHeader().getStructs();
- DeliveryProperties deliveryProps = new DeliveryProperties();
- deliveryProps.setRedelivered(true);
-
- List<Struct> list = Arrays.asList(structs);
- list.add(deliveryProps);
- xfr.setHeader(new Header(list));
- }
-
- }
- else
- {
- DeliveryProperties deliveryProps = new DeliveryProperties();
- deliveryProps.setRedelivered(true);
- xfr.setHeader(new Header(deliveryProps));
- }
+ ((MessageTransfer)m).getHeader().get(DeliveryProperties.class).setRedelivered(true);
}
sessionCommandPoint(m.getId(), 0);
send(m);
}
-
+
sessionCommandPoint(commandsOut, 0);
-
sessionFlush(COMPLETED);
resumer = Thread.currentThread();
state = RESUMING;
-
- if(isTransacted())
- {
- txSelect();
- }
-
listener.resumed(this);
resumer = null;
}
@@ -463,10 +422,7 @@ public class Session extends SessionInvoker
{
return;
}
- if (copy.size() > 0)
- {
- sessionCompleted(copy, options);
- }
+ sessionCompleted(copy, options);
}
}
@@ -576,6 +532,17 @@ public class Session extends SessionInvoker
{
if (m.getEncodedTrack() == Frame.L4)
{
+
+ if (state == DETACHED && transacted)
+ {
+ state = CLOSED;
+ delegate.closed(this);
+ connection.removeSession(this);
+ throw new SessionException(
+ "Session failed over, possibly in the middle of a transaction. " +
+ "Closing the session. Any Transaction in progress will be rolledback.");
+ }
+
if (m.hasPayload())
{
acquireCredit();
@@ -583,30 +550,24 @@ public class Session extends SessionInvoker
synchronized (commands)
{
- //allow the txSelect operation to be invoked during resume
- boolean skipWait = m instanceof TxSelect && state == RESUMING;
-
- if(!skipWait)
+ if (state == DETACHED && m.isUnreliable())
{
- if (state == DETACHED && m.isUnreliable())
+ Thread current = Thread.currentThread();
+ if (!current.equals(resumer))
{
- Thread current = Thread.currentThread();
- if (!current.equals(resumer))
- {
- return;
- }
+ return;
}
+ }
- if (state != OPEN && state != CLOSED && state != CLOSING)
+ if (state != OPEN && state != CLOSED && state != CLOSING)
+ {
+ Thread current = Thread.currentThread();
+ if (!current.equals(resumer))
{
- Thread current = Thread.currentThread();
- if (!current.equals(resumer))
+ Waiter w = new Waiter(commands, timeout);
+ while (w.hasTime() && (state != OPEN && state != CLOSED))
{
- Waiter w = new Waiter(commands, timeout);
- while (w.hasTime() && (state != OPEN && state != CLOSED))
- {
- w.await();
- }
+ w.await();
}
}
}
@@ -700,12 +661,7 @@ public class Session extends SessionInvoker
{
sessionCommandPoint(0, 0);
}
-
- boolean replayTransfer = !closing && !transacted &&
- m instanceof MessageTransfer &&
- ! m.isUnreliable();
-
- if ((replayTransfer) || m.hasCompletionListener())
+ if ((!closing && !transacted && m instanceof MessageTransfer) || m.hasCompletionListener())
{
commands[mod(next, commands.length)] = m;
commandBytes += m.getBodySize();
@@ -970,29 +926,16 @@ public class Session extends SessionInvoker
public void close()
{
- if (log.isDebugEnabled())
- {
- log.debug("Closing [%s] in state [%s]", this, state);
- }
synchronized (commands)
{
- switch(state)
- {
- case DETACHED:
- state = CLOSED;
- delegate.closed(this);
- connection.removeSession(this);
- listener.closed(this);
- break;
- case CLOSED:
- break;
- default:
- state = CLOSING;
- setClose(true);
- sessionRequestTimeout(0);
- sessionDetach(name.getBytes());
- awaitClose();
- }
+ state = CLOSING;
+ setClose(true);
+ sessionRequestTimeout(0);
+ sessionDetach(name.getBytes());
+
+ awaitClose();
+
+
}
}
@@ -1052,8 +995,7 @@ public class Session extends SessionInvoker
if(state == CLOSED)
{
- connection.removeSession(this);
- listener.closed(this);
+ connection.removeSession(this);
}
}
@@ -1066,55 +1008,13 @@ public class Session extends SessionInvoker
{
return String.format("ssn:%s", name);
}
-
+
public void setTransacted(boolean b) {
this.transacted = b;
}
-
+
public boolean isTransacted(){
return transacted;
}
-
- public void setDetachCode(SessionDetachCode dtc)
- {
- this.detachCode = dtc;
- }
-
- public SessionDetachCode getDetachCode()
- {
- return this.detachCode;
- }
-
- public void awaitOpen()
- {
- switch (state)
- {
- case NEW:
- synchronized(stateLock)
- {
- Waiter w = new Waiter(stateLock, timeout);
- while (w.hasTime() && state == NEW)
- {
- w.await();
- }
- }
-
- if (state != OPEN)
- {
- throw new SessionException("Timed out waiting for Session to open");
- }
- break;
- case DETACHED:
- case CLOSING:
- case CLOSED:
- throw new SessionException("Session closed");
- default :
- break;
- }
- }
-
- public Object getStateLock()
- {
- return stateLock;
- }
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/SessionDelegate.java b/java/common/src/main/java/org/apache/qpid/transport/SessionDelegate.java
index 3341149e5f..5d8e4d5565 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/SessionDelegate.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/SessionDelegate.java
@@ -76,10 +76,6 @@ public class SessionDelegate
@Override public void sessionAttached(Session ssn, SessionAttached atc)
{
ssn.setState(Session.State.OPEN);
- synchronized (ssn.getStateLock())
- {
- ssn.getStateLock().notifyAll();
- }
}
@Override public void sessionTimeout(Session ssn, SessionTimeout t)
@@ -206,19 +202,11 @@ public class SessionDelegate
public void closed(Session session)
{
- log.debug("CLOSED: [%s]", session);
- synchronized (session.getStateLock())
- {
- session.getStateLock().notifyAll();
- }
+ log.warn("CLOSED: [%s]", session);
}
public void detached(Session session)
{
- log.debug("DETACHED: [%s]", session);
- synchronized (session.getStateLock())
- {
- session.getStateLock().notifyAll();
- }
+ log.warn("DETACHED: [%s]", session);
}
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/TransportBuilder.java b/java/common/src/main/java/org/apache/qpid/transport/TransportBuilder.java
new file mode 100644
index 0000000000..c08909c6e4
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/TransportBuilder.java
@@ -0,0 +1,78 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.transport;
+
+import java.nio.ByteBuffer;
+
+import org.apache.qpid.transport.network.Assembler;
+import org.apache.qpid.transport.network.Disassembler;
+import org.apache.qpid.transport.network.InputHandler;
+import org.apache.qpid.transport.network.NetworkTransport;
+import org.apache.qpid.transport.network.Transport;
+import org.apache.qpid.transport.network.security.SecurityLayer;
+
+public class TransportBuilder
+{
+ private Connection con;
+ private ConnectionSettings settings;
+ private NetworkTransport transport;
+ private SecurityLayer securityLayer = new SecurityLayer();
+
+ public void init(Connection con) throws TransportException
+ {
+ this.con = con;
+ this.settings = con.getConnectionSettings();
+ transport = Transport.getTransport();
+ transport.init(settings);
+ securityLayer.init(con);
+ }
+
+ public Sender<ProtocolEvent> buildSenderPipe()
+ {
+ ConnectionSettings settings = con.getConnectionSettings();
+
+ // Io layer
+ Sender<ByteBuffer> sender = transport.sender();
+
+ // Security layer
+ sender = securityLayer.sender(sender);
+
+ Disassembler dis = new Disassembler(sender, settings.getMaxFrameSize());
+ return dis;
+ }
+
+ public void buildReceiverPipe(Receiver<ProtocolEvent> delegate)
+ {
+ Receiver<ByteBuffer> receiver = new InputHandler(new Assembler(delegate));
+
+ // Security layer
+ receiver = securityLayer.receiver(receiver);
+
+ //Io layer
+ transport.receiver(receiver);
+ }
+
+ public SecurityLayer getSecurityLayer()
+ {
+ return securityLayer;
+ }
+
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/transport/codec/AbstractEncoder.java b/java/common/src/main/java/org/apache/qpid/transport/codec/AbstractEncoder.java
index 0ccfcfcb70..908d14a307 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/codec/AbstractEncoder.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/codec/AbstractEncoder.java
@@ -63,7 +63,6 @@ abstract class AbstractEncoder implements Encoder
ENCODINGS.put(Double.class, Type.DOUBLE);
ENCODINGS.put(Character.class, Type.CHAR);
ENCODINGS.put(byte[].class, Type.VBIN32);
- ENCODINGS.put(UUID.class, Type.UUID);
}
private final Map<String,byte[]> str8cache = new LinkedHashMap<String,byte[]>()
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/IncomingNetworkTransport.java b/java/common/src/main/java/org/apache/qpid/transport/network/IncomingNetworkTransport.java
deleted file mode 100644
index b371df639e..0000000000
--- a/java/common/src/main/java/org/apache/qpid/transport/network/IncomingNetworkTransport.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.transport.network;
-
-import javax.net.ssl.SSLContext;
-
-import org.apache.qpid.protocol.ProtocolEngineFactory;
-import org.apache.qpid.transport.NetworkTransportConfiguration;
-
-public interface IncomingNetworkTransport extends NetworkTransport
-{
- public void accept(NetworkTransportConfiguration config, ProtocolEngineFactory factory, SSLContext sslContext);
-} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/NetworkConnection.java b/java/common/src/main/java/org/apache/qpid/transport/network/NetworkConnection.java
deleted file mode 100644
index 7384702525..0000000000
--- a/java/common/src/main/java/org/apache/qpid/transport/network/NetworkConnection.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.transport.network;
-
-import java.net.SocketAddress;
-import java.nio.ByteBuffer;
-
-import org.apache.qpid.transport.Sender;
-
-public interface NetworkConnection
-{
- Sender<ByteBuffer> getSender();
-
- void start();
-
- void close();
-
- /**
- * Returns the remote address of the underlying socket.
- */
- SocketAddress getRemoteAddress();
-
- /**
- * Returns the local address of the underlying socket.
- */
- SocketAddress getLocalAddress();
-
- void setMaxWriteIdle(int sec);
-
- void setMaxReadIdle(int sec);
-} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/NetworkTransport.java b/java/common/src/main/java/org/apache/qpid/transport/network/NetworkTransport.java
index f71d39c381..5e12d7e7c6 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/NetworkTransport.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/NetworkTransport.java
@@ -20,11 +20,19 @@
*/
package org.apache.qpid.transport.network;
-/**
- * A network transport is responsible for the establishment of network connections.
- * NetworkTransport implementations are pluggable via the {@link Transport} class.
- */
+import java.nio.ByteBuffer;
+
+import org.apache.qpid.transport.Receiver;
+import org.apache.qpid.transport.Sender;
+import org.apache.qpid.transport.ConnectionSettings;
+
public interface NetworkTransport
{
+ public void init(ConnectionSettings settings);
+
+ public Sender<ByteBuffer> sender();
+
+ public void receiver(Receiver<ByteBuffer> delegate);
+
public void close();
-}
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/OutgoingNetworkTransport.java b/java/common/src/main/java/org/apache/qpid/transport/network/OutgoingNetworkTransport.java
deleted file mode 100644
index c3c248761c..0000000000
--- a/java/common/src/main/java/org/apache/qpid/transport/network/OutgoingNetworkTransport.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.transport.network;
-
-import java.nio.ByteBuffer;
-
-import javax.net.ssl.SSLContext;
-
-import org.apache.qpid.transport.ConnectionSettings;
-import org.apache.qpid.transport.Receiver;
-
-public interface OutgoingNetworkTransport extends NetworkTransport
-{
- public NetworkConnection getConnection();
-
- public NetworkConnection connect(ConnectionSettings settings, Receiver<ByteBuffer> delegate, SSLContext sslContext);
-} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/Transport.java b/java/common/src/main/java/org/apache/qpid/transport/network/Transport.java
index da4349ba86..f0bf04d04f 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/Transport.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/Transport.java
@@ -1,5 +1,5 @@
/*
- *
+ *
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
@@ -7,128 +7,50 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
+ *
*/
-package org.apache.qpid.transport.network;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
+package org.apache.qpid.transport.network;
-import org.apache.qpid.framing.ProtocolVersion;
import org.apache.qpid.transport.TransportException;
public class Transport
-{
- public static final String QPID_TRANSPORT_PROPNAME = "qpid.transport";
- public static final String QPID_TRANSPORT_V0_8_PROPNAME = "qpid.transport.v0_8";
- public static final String QPID_TRANSPORT_V0_9_PROPNAME = "qpid.transport.v0_9";
- public static final String QPID_TRANSPORT_V0_9_1_PROPNAME = "qpid.transport.v0_9_1";
- public static final String QPID_TRANSPORT_V0_10_PROPNAME = "qpid.transport.v0_10";
- public static final String QPID_BROKER_TRANSPORT_PROPNAME = "qpid.broker.transport";
-
- // Can't reference the class directly here, as this would preclude the ability to bundle transports separately.
- private static final String IO_TRANSPORT_CLASSNAME = "org.apache.qpid.transport.network.io.IoNetworkTransport";
-
- public static final String TCP = "tcp";
-
- private final static Map<ProtocolVersion,String> OUTGOING_PROTOCOL_TO_IMPLDEFAULTS_MAP;
-
- static
- {
- final Map<ProtocolVersion,String> map = new HashMap<ProtocolVersion, String>();
- map.put(ProtocolVersion.v8_0, IO_TRANSPORT_CLASSNAME);
- map.put(ProtocolVersion.v0_9, IO_TRANSPORT_CLASSNAME);
- map.put(ProtocolVersion.v0_91, IO_TRANSPORT_CLASSNAME);
- map.put(ProtocolVersion.v0_10, IO_TRANSPORT_CLASSNAME);
-
- OUTGOING_PROTOCOL_TO_IMPLDEFAULTS_MAP = Collections.unmodifiableMap(map);
- }
-
- public static IncomingNetworkTransport getIncomingTransportInstance()
+{
+ private final static Class<?> transportClass;
+
+ static
{
- return (IncomingNetworkTransport) loadTransportClass(
- System.getProperty(QPID_BROKER_TRANSPORT_PROPNAME, IO_TRANSPORT_CLASSNAME));
- }
-
- public static OutgoingNetworkTransport getOutgoingTransportInstance(
- final ProtocolVersion protocolVersion)
- {
-
- final String overrride = getOverrideClassNameFromSystemProperty(protocolVersion);
- final String networkTransportClassName;
- if (overrride != null)
- {
- networkTransportClassName = overrride;
- }
- else
- {
- networkTransportClassName = OUTGOING_PROTOCOL_TO_IMPLDEFAULTS_MAP.get(protocolVersion);
- }
-
- return (OutgoingNetworkTransport) loadTransportClass(networkTransportClassName);
- }
-
- private static NetworkTransport loadTransportClass(final String networkTransportClassName)
- {
- if (networkTransportClassName == null)
- {
- throw new IllegalArgumentException("transport class name must not be null");
- }
-
try
{
- final Class<?> clazz = Class.forName(networkTransportClassName);
- return (NetworkTransport) clazz.newInstance();
+ transportClass =
+ Class.forName(System.getProperty("qpid.transport",
+ "org.apache.qpid.transport.network.io.IoNetworkTransport"));
+
}
- catch (InstantiationException e)
+ catch(Exception e)
{
- throw new TransportException("Unable to instantiate transport class " + networkTransportClassName, e);
- }
- catch (IllegalAccessException e)
- {
- throw new TransportException("Access exception " + networkTransportClassName, e);
- }
- catch (ClassNotFoundException e)
- {
- throw new TransportException("Unable to load transport class " + networkTransportClassName, e);
+ throw new Error("Error occured while loading Qpid Transport",e);
}
}
-
- private static String getOverrideClassNameFromSystemProperty(final ProtocolVersion protocolVersion)
+
+ public static NetworkTransport getTransport() throws TransportException
{
- final String protocolSpecificSystemProperty;
-
- if (ProtocolVersion.v0_10.equals(protocolVersion))
- {
- protocolSpecificSystemProperty = QPID_TRANSPORT_V0_10_PROPNAME;
- }
- else if (ProtocolVersion.v0_91.equals(protocolVersion))
- {
- protocolSpecificSystemProperty = QPID_TRANSPORT_V0_9_1_PROPNAME;
- }
- else if (ProtocolVersion.v0_9.equals(protocolVersion))
- {
- protocolSpecificSystemProperty = QPID_TRANSPORT_V0_9_PROPNAME;
- }
- else if (ProtocolVersion.v8_0.equals(protocolVersion))
+ try
{
- protocolSpecificSystemProperty = QPID_TRANSPORT_V0_8_PROPNAME;
+ return (NetworkTransport)transportClass.newInstance();
}
- else
+ catch (Exception e)
{
- throw new IllegalArgumentException("Unknown ProtocolVersion " + protocolVersion);
+ throw new TransportException("Error while creating a new transport instance",e);
}
-
- return System.getProperty(protocolSpecificSystemProperty, System.getProperty(QPID_TRANSPORT_PROPNAME));
}
-}
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/io/InputHandler_0_9.java b/java/common/src/main/java/org/apache/qpid/transport/network/io/InputHandler_0_9.java
new file mode 100644
index 0000000000..ecc5f6d07c
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/io/InputHandler_0_9.java
@@ -0,0 +1,130 @@
+package org.apache.qpid.transport.network.io;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+import java.nio.ByteBuffer;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQFrame;
+import org.apache.qpid.framing.AMQFrameDecodingException;
+import org.apache.qpid.framing.AMQMethodBody;
+import org.apache.qpid.framing.AMQMethodBodyFactory;
+import org.apache.qpid.framing.BodyFactory;
+import org.apache.qpid.framing.ContentBody;
+import org.apache.qpid.framing.ContentBodyFactory;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.ContentHeaderBodyFactory;
+import org.apache.qpid.framing.HeartbeatBody;
+import org.apache.qpid.framing.HeartbeatBodyFactory;
+import org.apache.qpid.framing.MethodRegistry;
+import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
+import org.apache.qpid.transport.Receiver;
+
+public class InputHandler_0_9 implements Receiver<ByteBuffer>
+{
+
+ private AMQVersionAwareProtocolSession _session;
+ private MethodRegistry _registry;
+ private BodyFactory bodyFactory;
+ private static final BodyFactory[] _bodiesSupported = new BodyFactory[Byte.MAX_VALUE];
+
+ static
+ {
+ _bodiesSupported[ContentHeaderBody.TYPE] = ContentHeaderBodyFactory.getInstance();
+ _bodiesSupported[ContentBody.TYPE] = ContentBodyFactory.getInstance();
+ _bodiesSupported[HeartbeatBody.TYPE] = new HeartbeatBodyFactory();
+ }
+
+ public InputHandler_0_9(AMQVersionAwareProtocolSession session)
+ {
+ _session = session;
+ _registry = _session.getMethodRegistry();
+ }
+
+ public void closed()
+ {
+ // AS FIXME: implement
+ }
+
+ public void exception(Throwable t)
+ {
+ // TODO: propogate exception to things
+ t.printStackTrace();
+ }
+
+ public void received(ByteBuffer buf)
+ {
+ org.apache.mina.common.ByteBuffer in = org.apache.mina.common.ByteBuffer.wrap(buf);
+ try
+ {
+ final byte type = in.get();
+ if (type == AMQMethodBody.TYPE)
+ {
+ bodyFactory = new AMQMethodBodyFactory(_session);
+ }
+ else
+ {
+ bodyFactory = _bodiesSupported[type];
+ }
+
+ if (bodyFactory == null)
+ {
+ throw new AMQFrameDecodingException(null, "Unsupported frame type: " + type, null);
+ }
+
+ final int channel = in.getUnsignedShort();
+ final long bodySize = in.getUnsignedInt();
+
+ // bodySize can be zero
+ if ((channel < 0) || (bodySize < 0))
+ {
+ throw new AMQFrameDecodingException(null, "Undecodable frame: type = " + type + " channel = " + channel
+ + " bodySize = " + bodySize, null);
+ }
+
+ AMQFrame frame = new AMQFrame(in, channel, bodySize, bodyFactory);
+
+ byte marker = in.get();
+ if ((marker & 0xFF) != 0xCE)
+ {
+ throw new AMQFrameDecodingException(null, "End of frame marker not found. Read " + marker + " length=" + bodySize
+ + " type=" + type, null);
+ }
+
+ try
+ {
+ frame.getBodyFrame().handle(frame.getChannel(), _session);
+ }
+ catch (AMQException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+ catch (AMQFrameDecodingException e)
+ {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+}
diff --git a/java/common/src/test/java/org/apache/qpid/transport/network/io/IoAcceptor.java b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoAcceptor.java
index e075681acb..8530240dcc 100644
--- a/java/common/src/test/java/org/apache/qpid/transport/network/io/IoAcceptor.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoAcceptor.java
@@ -80,7 +80,7 @@ public class IoAcceptor<E> extends Thread
try
{
Socket sock = socket.accept();
- IoTransport<E> transport = new IoTransport<E>(sock, binding);
+ IoTransport<E> transport = new IoTransport<E>(sock, binding,false);
}
catch (IOException e)
{
diff --git a/java/common/src/test/java/org/apache/qpid/transport/MockSender.java b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoContext.java
index 4b38b7318a..69b3a0ce45 100644
--- a/java/common/src/test/java/org/apache/qpid/transport/MockSender.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoContext.java
@@ -1,5 +1,5 @@
/*
- *
+ *
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
@@ -7,41 +7,29 @@
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
- *
+ *
*/
-package org.apache.qpid.transport;
+package org.apache.qpid.transport.network.io;
+import java.net.Socket;
import java.nio.ByteBuffer;
-public class MockSender implements Sender<ByteBuffer>
-{
-
- public void setIdleTimeout(int i)
- {
-
- }
-
- public void send(ByteBuffer msg)
- {
+import org.apache.qpid.transport.Sender;
- }
-
- public void flush()
- {
-
- }
-
- public void close()
- {
+public interface IoContext
+{
+ Sender<ByteBuffer> getSender();
+
+ IoReceiver getReceiver();
- }
+ Socket getSocket();
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkConnection.java b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkConnection.java
deleted file mode 100644
index bfc77539ce..0000000000
--- a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkConnection.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
-*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.transport.network.io;
-
-import java.net.Socket;
-import java.net.SocketAddress;
-import java.nio.ByteBuffer;
-
-import org.apache.qpid.transport.Receiver;
-import org.apache.qpid.transport.Sender;
-import org.apache.qpid.transport.network.NetworkConnection;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class IoNetworkConnection implements NetworkConnection
-{
- private static final Logger LOGGER = LoggerFactory.getLogger(IoNetworkConnection.class);
- private final Socket _socket;
- private final long _timeout;
- private final IoSender _ioSender;
- private final IoReceiver _ioReceiver;
-
- public IoNetworkConnection(Socket socket, Receiver<ByteBuffer> delegate,
- int sendBufferSize, int receiveBufferSize, long timeout)
- {
- _socket = socket;
- _timeout = timeout;
-
- _ioReceiver = new IoReceiver(_socket, delegate, receiveBufferSize,_timeout);
-
- _ioSender = new IoSender(_socket, 2 * sendBufferSize, _timeout);
-
- _ioSender.registerCloseListener(_ioReceiver);
-
- }
-
- public void start()
- {
- _ioSender.initiate();
- _ioReceiver.initiate();
- }
-
- public Sender<ByteBuffer> getSender()
- {
- return _ioSender;
- }
-
- public void close()
- {
- try
- {
- _ioSender.close();
- }
- finally
- {
- _ioReceiver.close(false);
- }
- }
-
- public SocketAddress getRemoteAddress()
- {
- return _socket.getRemoteSocketAddress();
- }
-
- public SocketAddress getLocalAddress()
- {
- return _socket.getLocalSocketAddress();
- }
-
- public void setMaxWriteIdle(int sec)
- {
- // TODO implement support for setting heartbeating config in this way
- // Currently a socket timeout is used in IoSender
- }
-
- public void setMaxReadIdle(int sec)
- {
- // TODO implement support for setting heartbeating config in this way
- // Currently a socket timeout is used in IoSender
- }
-}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java
index e1d1596ec5..dd6a37eca2 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoNetworkTransport.java
@@ -21,49 +21,57 @@
package org.apache.qpid.transport.network.io;
import java.io.IOException;
-import java.net.*;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketException;
import java.nio.ByteBuffer;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLServerSocketFactory;
-
-import org.apache.qpid.protocol.ProtocolEngine;
-import org.apache.qpid.protocol.ProtocolEngineFactory;
-import org.apache.qpid.transport.*;
-import org.apache.qpid.transport.network.IncomingNetworkTransport;
-import org.apache.qpid.transport.network.NetworkConnection;
-import org.apache.qpid.transport.network.OutgoingNetworkTransport;
+import org.apache.qpid.transport.ConnectionSettings;
+import org.apache.qpid.transport.Receiver;
+import org.apache.qpid.transport.Sender;
+import org.apache.qpid.transport.TransportException;
+import org.apache.qpid.transport.network.NetworkTransport;
import org.apache.qpid.transport.util.Logger;
-public class IoNetworkTransport implements OutgoingNetworkTransport, IncomingNetworkTransport
+public class IoNetworkTransport implements NetworkTransport, IoContext
{
+ static
+ {
+ org.apache.mina.common.ByteBuffer.setAllocator
+ (new org.apache.mina.common.SimpleByteBufferAllocator());
+ org.apache.mina.common.ByteBuffer.setUseDirectBuffers
+ (Boolean.getBoolean("amqj.enableDirectBuffers"));
+ }
- private static final Logger LOGGER = Logger.get(IoNetworkTransport.class);
-
- private Socket _socket;
- private IoNetworkConnection _connection;
- private long _timeout = 60000;
- private AcceptingThread _acceptor;
+ private static final Logger log = Logger.get(IoNetworkTransport.class);
- public NetworkConnection connect(ConnectionSettings settings, Receiver<ByteBuffer> delegate, SSLContext sslContext)
+ private Socket socket;
+ private Sender<ByteBuffer> sender;
+ private IoReceiver receiver;
+ private long timeout = 60000;
+ private ConnectionSettings settings;
+
+ public void init(ConnectionSettings settings)
{
- int sendBufferSize = settings.getWriteBufferSize();
- int receiveBufferSize = settings.getReadBufferSize();
-
try
{
- _socket = new Socket();
- _socket.setReuseAddress(true);
- _socket.setTcpNoDelay(settings.isTcpNodelay());
- _socket.setSendBufferSize(sendBufferSize);
- _socket.setReceiveBufferSize(receiveBufferSize);
+ this.settings = settings;
+ InetAddress address = InetAddress.getByName(settings.getHost());
+ socket = new Socket();
+ socket.setReuseAddress(true);
+ socket.setTcpNoDelay(settings.isTcpNodelay());
- LOGGER.debug("SO_RCVBUF : %s", _socket.getReceiveBufferSize());
- LOGGER.debug("SO_SNDBUF : %s", _socket.getSendBufferSize());
+ log.debug("default-SO_RCVBUF : %s", socket.getReceiveBufferSize());
+ log.debug("default-SO_SNDBUF : %s", socket.getSendBufferSize());
- InetAddress address = InetAddress.getByName(settings.getHost());
+ socket.setSendBufferSize(settings.getWriteBufferSize());
+ socket.setReceiveBufferSize(settings.getReadBufferSize());
+
+ log.debug("new-SO_RCVBUF : %s", socket.getReceiveBufferSize());
+ log.debug("new-SO_SNDBUF : %s", socket.getSendBufferSize());
- _socket.connect(new InetSocketAddress(address, settings.getPort()));
+ socket.connect(new InetSocketAddress(address, settings.getPort()));
}
catch (SocketException e)
{
@@ -73,159 +81,36 @@ public class IoNetworkTransport implements OutgoingNetworkTransport, IncomingNet
{
throw new TransportException("Error connecting to broker", e);
}
+ }
- try
- {
- _connection = new IoNetworkConnection(_socket, delegate, sendBufferSize, receiveBufferSize, _timeout);
- _connection.start();
- }
- catch(Exception e)
- {
- try
- {
- _socket.close();
- }
- catch(IOException ioe)
- {
- //ignored, throw based on original exception
- }
-
- throw new TransportException("Error creating network connection", e);
- }
+ public void receiver(Receiver<ByteBuffer> delegate)
+ {
+ receiver = new IoReceiver(this, delegate,
+ 2*settings.getReadBufferSize() , timeout);
+ }
- return _connection;
+ public Sender<ByteBuffer> sender()
+ {
+ return new IoSender(this, 2*settings.getWriteBufferSize(), timeout);
}
public void close()
{
- if(_connection != null)
- {
- _connection.close();
- }
- if(_acceptor != null)
- {
- _acceptor.close();
- }
+
}
- public NetworkConnection getConnection()
+ public Sender<ByteBuffer> getSender()
{
- return _connection;
+ return sender;
}
- public void accept(NetworkTransportConfiguration config, ProtocolEngineFactory factory, SSLContext sslContext)
+ public IoReceiver getReceiver()
{
-
- try
- {
- _acceptor = new AcceptingThread(config, factory, sslContext);
-
- _acceptor.start();
- }
- catch (IOException e)
- {
- throw new TransportException("Unable to start server socket", e);
- }
-
-
+ return receiver;
}
- private class AcceptingThread extends Thread
+ public Socket getSocket()
{
- private NetworkTransportConfiguration _config;
- private ProtocolEngineFactory _factory;
- private SSLContext _sslContent;
- private ServerSocket _serverSocket;
-
- private AcceptingThread(NetworkTransportConfiguration config,
- ProtocolEngineFactory factory,
- SSLContext sslContext)
- throws IOException
- {
- _config = config;
- _factory = factory;
- _sslContent = sslContext;
-
- InetSocketAddress address = new InetSocketAddress(config.getHost(), config.getPort());
-
- if(sslContext == null)
- {
- _serverSocket = new ServerSocket();
- }
- else
- {
- SSLServerSocketFactory socketFactory = sslContext.getServerSocketFactory();
- _serverSocket = socketFactory.createServerSocket();
- }
-
- _serverSocket.bind(address);
- _serverSocket.setReuseAddress(true);
-
-
- }
-
-
- /**
- Close the underlying ServerSocket if it has not already been closed.
- */
- public void close()
- {
- if (!_serverSocket.isClosed())
- {
- try
- {
- _serverSocket.close();
- }
- catch (IOException e)
- {
- throw new TransportException(e);
- }
- }
- }
-
- @Override
- public void run()
- {
- try
- {
- while (true)
- {
- try
- {
- Socket socket = _serverSocket.accept();
- socket.setTcpNoDelay(_config.getTcpNoDelay());
-
- final Integer sendBufferSize = _config.getSendBufferSize();
- final Integer receiveBufferSize = _config.getReceiveBufferSize();
-
- socket.setSendBufferSize(sendBufferSize);
- socket.setReceiveBufferSize(receiveBufferSize);
-
- ProtocolEngine engine = _factory.newProtocolEngine();
-
- NetworkConnection connection = new IoNetworkConnection(socket, engine, sendBufferSize, receiveBufferSize, _timeout);
-
-
- engine.setNetworkConnection(connection, connection.getSender());
-
- connection.start();
-
-
- }
- catch(RuntimeException e)
- {
- LOGGER.error(e, "Error in Acceptor thread " + _config.getPort());
- }
- }
- }
- catch (IOException e)
- {
- LOGGER.debug(e, "SocketException - no new connections will be accepted on port "
- + _config.getPort());
- }
- }
-
-
+ return socket;
}
-
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java
index d4b5975e54..19a683d505 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java
@@ -20,7 +20,6 @@
*/
package org.apache.qpid.transport.network.io;
-import org.apache.qpid.common.Closeable;
import org.apache.qpid.thread.Threading;
import org.apache.qpid.transport.Receiver;
import org.apache.qpid.transport.TransportException;
@@ -38,77 +37,56 @@ import java.util.concurrent.atomic.AtomicBoolean;
*
*/
-final class IoReceiver implements Runnable, Closeable
+final class IoReceiver implements Runnable
{
private static final Logger log = Logger.get(IoReceiver.class);
+ private final IoContext ioCtx;
private final Receiver<ByteBuffer> receiver;
private final int bufferSize;
private final Socket socket;
private final long timeout;
private final AtomicBoolean closed = new AtomicBoolean(false);
private final Thread receiverThread;
- private static final boolean shutdownBroken;
- static
- {
- String osName = System.getProperty("os.name");
- shutdownBroken = osName == null ? false : osName.matches("(?i).*windows.*");
- }
+ private final boolean shutdownBroken =
+ ((String) System.getProperties().get("os.name")).matches("(?i).*windows.*");
- public IoReceiver(Socket socket, Receiver<ByteBuffer> receiver, int bufferSize, long timeout)
+ public IoReceiver(IoContext ioCtx, Receiver<ByteBuffer> receiver,
+ int bufferSize, long timeout)
{
+ this.ioCtx = ioCtx;
this.receiver = receiver;
this.bufferSize = bufferSize;
- this.socket = socket;
+ this.socket = ioCtx.getSocket();
this.timeout = timeout;
try
{
- //Create but deliberately don't start the thread.
receiverThread = Threading.getThreadFactory().createThread(this);
}
catch(Exception e)
{
- throw new RuntimeException("Error creating IOReceiver thread",e);
+ throw new Error("Error creating IOReceiver thread",e);
}
receiverThread.setDaemon(true);
receiverThread.setName(String.format("IoReceiver - %s", socket.getRemoteSocketAddress()));
- }
-
- public void initiate()
- {
receiverThread.start();
}
- public void close()
- {
- close(false);
- }
-
void close(boolean block)
{
if (!closed.getAndSet(true))
{
try
{
- try
+ if (shutdownBroken)
{
- if (shutdownBroken)
- {
- socket.close();
- }
- else
- {
- socket.shutdownInput();
- }
+ socket.close();
}
- catch(SocketException se)
+ else
{
- if(!socket.isClosed() && !socket.isInputShutdown())
- {
- throw se;
- }
+ socket.shutdownInput();
}
if (block && Thread.currentThread() != receiverThread)
{
@@ -127,7 +105,6 @@ final class IoReceiver implements Runnable, Closeable
{
throw new TransportException(e);
}
-
}
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoSender.java b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoSender.java
index 427487c879..66b97e8225 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoSender.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoSender.java
@@ -24,14 +24,10 @@ import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
-import org.apache.qpid.common.Closeable;
import org.apache.qpid.thread.Threading;
import org.apache.qpid.transport.Sender;
-import org.apache.qpid.transport.SenderClosedException;
import org.apache.qpid.transport.SenderException;
import org.apache.qpid.transport.TransportException;
import org.apache.qpid.transport.util.Logger;
@@ -47,6 +43,7 @@ public final class IoSender implements Runnable, Sender<ByteBuffer>
// we can test other cases as well
private final static int START = Integer.MAX_VALUE - 10;
+ private final IoContext ioCtx;
private final long timeout;
private final Socket socket;
private final OutputStream out;
@@ -59,13 +56,14 @@ public final class IoSender implements Runnable, Sender<ByteBuffer>
private final Object notEmpty = new Object();
private final AtomicBoolean closed = new AtomicBoolean(false);
private final Thread senderThread;
- private final List<Closeable> _listeners = new ArrayList<Closeable>();
-
+
private volatile Throwable exception = null;
- public IoSender(Socket socket, int bufferSize, long timeout)
+
+ public IoSender(IoContext ioCtx, int bufferSize, long timeout)
{
- this.socket = socket;
+ this.ioCtx = ioCtx;
+ this.socket = ioCtx.getSocket();
this.buffer = new byte[pof2(bufferSize)]; // buffer size must be a power of 2
this.timeout = timeout;
@@ -80,20 +78,15 @@ public final class IoSender implements Runnable, Sender<ByteBuffer>
try
{
- //Create but deliberately don't start the thread.
- senderThread = Threading.getThreadFactory().createThread(this);
+ senderThread = Threading.getThreadFactory().createThread(this);
}
catch(Exception e)
{
throw new Error("Error creating IOSender thread",e);
}
-
+
senderThread.setDaemon(true);
senderThread.setName(String.format("IoSender - %s", socket.getRemoteSocketAddress()));
- }
-
- public void initiate()
- {
senderThread.start();
}
@@ -111,11 +104,7 @@ public final class IoSender implements Runnable, Sender<ByteBuffer>
{
if (closed.get())
{
- throw new SenderClosedException("sender is closed", exception);
- }
- if(!senderThread.isAlive())
- {
- throw new SenderException("sender thread not alive");
+ throw new SenderException("sender is closed", exception);
}
final int size = buffer.length;
@@ -148,7 +137,7 @@ public final class IoSender implements Runnable, Sender<ByteBuffer>
if (closed.get())
{
- throw new SenderClosedException("sender is closed", exception);
+ throw new SenderException("sender is closed", exception);
}
if (head - tail >= size)
@@ -215,20 +204,16 @@ public final class IoSender implements Runnable, Sender<ByteBuffer>
senderThread.join(timeout);
if (senderThread.isAlive())
{
- log.error("join timed out");
throw new SenderException("join timed out");
}
}
+ ioCtx.getReceiver().close(false);
}
catch (InterruptedException e)
{
- log.error("interrupted whilst waiting for sender thread to stop");
throw new SenderException(e);
}
- finally
- {
- closeListeners();
- }
+
if (reportException && exception != null)
{
throw new SenderException(exception);
@@ -236,31 +221,9 @@ public final class IoSender implements Runnable, Sender<ByteBuffer>
}
}
- private void closeListeners()
- {
- Exception ex = null;
- for(Closeable listener : _listeners)
- {
- try
- {
- listener.close();
- }
- catch(Exception e)
- {
- log.error("Exception closing listener: " + e.getMessage());
- ex = e;
- }
- }
-
- if (ex != null)
- {
- throw new SenderException(ex.getMessage(), ex);
- }
- }
-
public void run()
{
- final int size = buffer.length;
+ final int size = buffer.length;
while (true)
{
final int hd = head;
@@ -341,9 +304,4 @@ public final class IoSender implements Runnable, Sender<ByteBuffer>
throw new SenderException(e);
}
}
-
- public void registerCloseListener(Closeable listener)
- {
- _listeners.add(listener);
- }
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoTransport.java b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoTransport.java
new file mode 100644
index 0000000000..bfdbb34978
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoTransport.java
@@ -0,0 +1,231 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.qpid.transport.network.io;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+
+import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
+import org.apache.qpid.ssl.SSLContextFactory;
+import org.apache.qpid.transport.Binding;
+import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.ConnectionDelegate;
+import org.apache.qpid.transport.Receiver;
+import org.apache.qpid.transport.Sender;
+import org.apache.qpid.transport.TransportException;
+import org.apache.qpid.transport.network.ConnectionBinding;
+import org.apache.qpid.transport.network.security.ssl.SSLReceiver;
+import org.apache.qpid.transport.network.security.ssl.SSLSender;
+import org.apache.qpid.transport.util.Logger;
+
+/**
+ * This class provides a socket based transport using the java.io
+ * classes.
+ *
+ * The following params are configurable via JVM arguments
+ * TCP_NO_DELAY - amqj.tcpNoDelay
+ * SO_RCVBUF - amqj.receiveBufferSize
+ * SO_SNDBUF - amqj.sendBufferSize
+ */
+public final class IoTransport<E> implements IoContext
+{
+
+ static
+ {
+ org.apache.mina.common.ByteBuffer.setAllocator
+ (new org.apache.mina.common.SimpleByteBufferAllocator());
+ org.apache.mina.common.ByteBuffer.setUseDirectBuffers
+ (Boolean.getBoolean("amqj.enableDirectBuffers"));
+ }
+
+ private static final Logger log = Logger.get(IoTransport.class);
+
+ private static int DEFAULT_READ_WRITE_BUFFER_SIZE = 64 * 1024;
+ private static int readBufferSize = Integer.getInteger
+ ("amqj.receiveBufferSize", DEFAULT_READ_WRITE_BUFFER_SIZE);
+ private static int writeBufferSize = Integer.getInteger
+ ("amqj.sendBufferSize", DEFAULT_READ_WRITE_BUFFER_SIZE);
+
+ private Socket socket;
+ private Sender<ByteBuffer> sender;
+ private E endpoint;
+ private IoReceiver receiver;
+ private long timeout = 60000;
+
+ IoTransport(Socket socket, Binding<E,ByteBuffer> binding, boolean ssl)
+ {
+ this.socket = socket;
+
+ if (ssl)
+ {
+ SSLEngine engine = null;
+ SSLContext sslCtx;
+ try
+ {
+ sslCtx = createSSLContext();
+ }
+ catch (Exception e)
+ {
+ throw new TransportException("Error creating SSL Context", e);
+ }
+
+ try
+ {
+ engine = sslCtx.createSSLEngine();
+ engine.setUseClientMode(true);
+ }
+ catch(Exception e)
+ {
+ throw new TransportException("Error creating SSL Engine", e);
+ }
+
+ this.sender = new SSLSender(engine,new IoSender(this, 2*writeBufferSize, timeout));
+ this.endpoint = binding.endpoint(sender);
+ this.receiver = new IoReceiver(this, new SSLReceiver(engine,binding.receiver(endpoint),(SSLSender)sender),
+ 2*readBufferSize, timeout);
+
+ log.info("SSL Sender and Receiver initiated");
+ }
+ else
+ {
+ this.sender = new IoSender(this, 2*writeBufferSize, timeout);
+ this.endpoint = binding.endpoint(sender);
+ this.receiver = new IoReceiver(this, binding.receiver(endpoint),
+ 2*readBufferSize, timeout);
+ }
+ }
+
+ public Sender<ByteBuffer> getSender()
+ {
+ return sender;
+ }
+
+ public IoReceiver getReceiver()
+ {
+ return receiver;
+ }
+
+ public Socket getSocket()
+ {
+ return socket;
+ }
+
+ public static final <E> E connect(String host, int port,
+ Binding<E,ByteBuffer> binding,
+ boolean ssl)
+ {
+ Socket socket = createSocket(host, port);
+ IoTransport<E> transport = new IoTransport<E>(socket, binding,ssl);
+ return transport.endpoint;
+ }
+
+ public static final Connection connect(String host, int port,
+ ConnectionDelegate delegate,
+ boolean ssl)
+ {
+ return connect(host, port, ConnectionBinding.get(delegate),ssl);
+ }
+
+ public static void connect_0_9(AMQVersionAwareProtocolSession session, String host, int port, boolean ssl)
+ {
+ connect(host, port, new Binding_0_9(session),ssl);
+ }
+
+ private static class Binding_0_9
+ implements Binding<AMQVersionAwareProtocolSession,ByteBuffer>
+ {
+
+ private AMQVersionAwareProtocolSession session;
+
+ Binding_0_9(AMQVersionAwareProtocolSession session)
+ {
+ this.session = session;
+ }
+
+ public AMQVersionAwareProtocolSession endpoint(Sender<ByteBuffer> sender)
+ {
+ session.setSender(sender);
+ return session;
+ }
+
+ public Receiver<ByteBuffer> receiver(AMQVersionAwareProtocolSession ssn)
+ {
+ return new InputHandler_0_9(ssn);
+ }
+
+ }
+
+ private static Socket createSocket(String host, int port)
+ {
+ try
+ {
+ InetAddress address = InetAddress.getByName(host);
+ Socket socket = new Socket();
+ socket.setReuseAddress(true);
+ socket.setTcpNoDelay(Boolean.getBoolean("amqj.tcpNoDelay"));
+
+ log.debug("default-SO_RCVBUF : %s", socket.getReceiveBufferSize());
+ log.debug("default-SO_SNDBUF : %s", socket.getSendBufferSize());
+
+ socket.setSendBufferSize(writeBufferSize);
+ socket.setReceiveBufferSize(readBufferSize);
+
+ log.debug("new-SO_RCVBUF : %s", socket.getReceiveBufferSize());
+ log.debug("new-SO_SNDBUF : %s", socket.getSendBufferSize());
+
+ socket.connect(new InetSocketAddress(address, port));
+ return socket;
+ }
+ catch (SocketException e)
+ {
+ throw new TransportException("Error connecting to broker", e);
+ }
+ catch (IOException e)
+ {
+ throw new TransportException("Error connecting to broker", e);
+ }
+ }
+
+ private SSLContext createSSLContext() throws Exception
+ {
+ String trustStorePath = System.getProperty("javax.net.ssl.trustStore");
+ String trustStorePassword = System.getProperty("javax.net.ssl.trustStorePassword");
+ String trustStoreCertType = System.getProperty("qpid.ssl.trustStoreCertType","SunX509");
+
+ String keyStorePath = System.getProperty("javax.net.ssl.keyStore",trustStorePath);
+ String keyStorePassword = System.getProperty("javax.net.ssl.keyStorePassword",trustStorePassword);
+ String keyStoreCertType = System.getProperty("qpid.ssl.keyStoreCertType","SunX509");
+
+ SSLContextFactory sslContextFactory = new SSLContextFactory(trustStorePath,trustStorePassword,
+ trustStoreCertType,keyStorePath,
+ keyStorePassword,keyStoreCertType);
+
+ return sslContextFactory.buildServerContext();
+
+ }
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java b/java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java
new file mode 100644
index 0000000000..0f2c0d0226
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java
@@ -0,0 +1,435 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.transport.network.mina;
+
+import org.apache.mina.common.ConnectFuture;
+import org.apache.mina.common.ExecutorThreadModel;
+import org.apache.mina.common.IdleStatus;
+import org.apache.mina.common.IoAcceptor;
+import org.apache.mina.common.IoConnector;
+import org.apache.mina.common.IoFilterChain;
+import org.apache.mina.common.IoHandlerAdapter;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.common.SimpleByteBufferAllocator;
+import org.apache.mina.common.WriteFuture;
+import org.apache.mina.filter.ReadThrottleFilterBuilder;
+import org.apache.mina.filter.SSLFilter;
+import org.apache.mina.filter.WriteBufferLimitFilterBuilder;
+import org.apache.mina.filter.executor.ExecutorFilter;
+import org.apache.mina.transport.socket.nio.MultiThreadSocketConnector;
+import org.apache.mina.transport.socket.nio.SocketAcceptorConfig;
+import org.apache.mina.transport.socket.nio.SocketConnector;
+import org.apache.mina.transport.socket.nio.SocketConnectorConfig;
+import org.apache.mina.transport.socket.nio.SocketSessionConfig;
+import org.apache.mina.util.NewThreadExecutor;
+import org.apache.mina.util.SessionUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import org.apache.qpid.protocol.ProtocolEngine;
+import org.apache.qpid.protocol.ProtocolEngineFactory;
+import org.apache.qpid.ssl.SSLContextFactory;
+import org.apache.qpid.thread.QpidThreadExecutor;
+import org.apache.qpid.transport.NetworkDriver;
+import org.apache.qpid.transport.NetworkDriverConfiguration;
+import org.apache.qpid.transport.OpenException;
+
+import java.io.IOException;
+import java.net.BindException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+
+public class MINANetworkDriver extends IoHandlerAdapter implements NetworkDriver
+{
+
+ private static final int DEFAULT_BUFFER_SIZE = 32 * 1024;
+
+ ProtocolEngine _protocolEngine;
+ private boolean _useNIO = false;
+ private int _processors = 4;
+ private boolean _executorPool = false;
+ private SSLContextFactory _sslFactory = null;
+ private IoConnector _socketConnector;
+ private IoAcceptor _acceptor;
+ private IoSession _ioSession;
+ private ProtocolEngineFactory _factory;
+ private boolean _protectIO;
+ private NetworkDriverConfiguration _config;
+ private Throwable _lastException;
+ private boolean _acceptingConnections = false;
+
+ private WriteFuture _lastWriteFuture;
+
+ private static final Logger _logger = LoggerFactory.getLogger(MINANetworkDriver.class);
+
+ static
+ {
+ org.apache.mina.common.ByteBuffer.setUseDirectBuffers(Boolean.getBoolean("amqj.enableDirectBuffers"));
+
+ //override the MINA defaults to prevent use of the PooledByteBufferAllocator
+ org.apache.mina.common.ByteBuffer.setAllocator(new SimpleByteBufferAllocator());
+ }
+
+ public MINANetworkDriver(boolean useNIO, int processors, boolean executorPool, boolean protectIO)
+ {
+ _useNIO = useNIO;
+ _processors = processors;
+ _executorPool = executorPool;
+ _protectIO = protectIO;
+ }
+
+ public MINANetworkDriver(boolean useNIO, int processors, boolean executorPool, boolean protectIO,
+ ProtocolEngine protocolEngine, IoSession session)
+ {
+ _useNIO = useNIO;
+ _processors = processors;
+ _executorPool = executorPool;
+ _protectIO = protectIO;
+ _protocolEngine = protocolEngine;
+ _ioSession = session;
+ _ioSession.setAttachment(_protocolEngine);
+ }
+
+ public MINANetworkDriver()
+ {
+
+ }
+
+ public MINANetworkDriver(IoConnector ioConnector)
+ {
+ _socketConnector = ioConnector;
+ }
+
+ public MINANetworkDriver(IoConnector ioConnector, ProtocolEngine engine)
+ {
+ _socketConnector = ioConnector;
+ _protocolEngine = engine;
+ }
+
+ public void bind(int port, InetAddress[] addresses, ProtocolEngineFactory factory,
+ NetworkDriverConfiguration config, SSLContextFactory sslFactory) throws BindException
+ {
+
+ _factory = factory;
+ _config = config;
+
+ if (_useNIO)
+ {
+ _acceptor = new org.apache.mina.transport.socket.nio.MultiThreadSocketAcceptor(_processors,
+ new NewThreadExecutor());
+ }
+ else
+ {
+ _acceptor = new org.apache.mina.transport.socket.nio.SocketAcceptor(_processors, new NewThreadExecutor());
+ }
+
+ SocketAcceptorConfig sconfig = (SocketAcceptorConfig) _acceptor.getDefaultConfig();
+ sconfig.setThreadModel(ExecutorThreadModel.getInstance("MINANetworkDriver(Acceptor)"));
+ SocketSessionConfig sc = (SocketSessionConfig) sconfig.getSessionConfig();
+
+ if (config != null)
+ {
+ sc.setReceiveBufferSize(config.getReceiveBufferSize());
+ sc.setSendBufferSize(config.getSendBufferSize());
+ sc.setTcpNoDelay(config.getTcpNoDelay());
+ }
+
+ if (sslFactory != null)
+ {
+ _sslFactory = sslFactory;
+ }
+
+ if (addresses != null && addresses.length > 0)
+ {
+ for (InetAddress addr : addresses)
+ {
+ try
+ {
+ _acceptor.bind(new InetSocketAddress(addr, port), this, sconfig);
+ }
+ catch (IOException e)
+ {
+ throw new BindException(String.format("Could not bind to %1s:%2s", addr, port));
+ }
+ }
+ }
+ else
+ {
+ try
+ {
+ _acceptor.bind(new InetSocketAddress(port), this, sconfig);
+ }
+ catch (IOException e)
+ {
+ throw new BindException(String.format("Could not bind to *:%1s", port));
+ }
+ }
+ _acceptingConnections = true;
+ }
+
+ public SocketAddress getRemoteAddress()
+ {
+ return _ioSession.getRemoteAddress();
+ }
+
+ public SocketAddress getLocalAddress()
+ {
+ return _ioSession.getLocalAddress();
+ }
+
+
+ public void open(int port, InetAddress destination, ProtocolEngine engine, NetworkDriverConfiguration config,
+ SSLContextFactory sslFactory) throws OpenException
+ {
+ if (sslFactory != null)
+ {
+ _sslFactory = sslFactory;
+ }
+
+ if (_useNIO)
+ {
+ _socketConnector = new MultiThreadSocketConnector(1, new QpidThreadExecutor());
+ }
+ else
+ {
+ _socketConnector = new SocketConnector(1, new QpidThreadExecutor()); // non-blocking
+ // connector
+ }
+
+ SocketConnectorConfig cfg = (SocketConnectorConfig) _socketConnector.getDefaultConfig();
+ String s = "";
+ StackTraceElement[] trace = Thread.currentThread().getStackTrace();
+ for(StackTraceElement elt : trace)
+ {
+ if(elt.getClassName().contains("Test"))
+ {
+ s = elt.getClassName();
+ break;
+ }
+ }
+ cfg.setThreadModel(ExecutorThreadModel.getInstance("MINANetworkDriver(Client)-"+s));
+
+ SocketSessionConfig scfg = (SocketSessionConfig) cfg.getSessionConfig();
+ scfg.setTcpNoDelay((config != null) ? config.getTcpNoDelay() : true);
+ scfg.setSendBufferSize((config != null) ? config.getSendBufferSize() : DEFAULT_BUFFER_SIZE);
+ scfg.setReceiveBufferSize((config != null) ? config.getReceiveBufferSize() : DEFAULT_BUFFER_SIZE);
+
+ // Don't have the connector's worker thread wait around for other
+ // connections (we only use
+ // one SocketConnector per connection at the moment anyway). This allows
+ // short-running
+ // clients (like unit tests) to complete quickly.
+ if (_socketConnector instanceof SocketConnector)
+ {
+ ((SocketConnector) _socketConnector).setWorkerTimeout(0);
+ }
+
+ ConnectFuture future = _socketConnector.connect(new InetSocketAddress(destination, port), this, cfg);
+ future.join();
+ if (!future.isConnected())
+ {
+ throw new OpenException("Could not open connection", _lastException);
+ }
+ _ioSession = future.getSession();
+ _ioSession.setAttachment(engine);
+ engine.setNetworkDriver(this);
+ _protocolEngine = engine;
+ }
+
+ public void setMaxReadIdle(int idleTime)
+ {
+ _ioSession.setIdleTime(IdleStatus.READER_IDLE, idleTime);
+ }
+
+ public void setMaxWriteIdle(int idleTime)
+ {
+ _ioSession.setIdleTime(IdleStatus.WRITER_IDLE, idleTime);
+ }
+
+ public void close()
+ {
+ if (_lastWriteFuture != null)
+ {
+ _lastWriteFuture.join();
+ }
+ if (_acceptor != null)
+ {
+ _acceptor.unbindAll();
+ }
+ if (_ioSession != null)
+ {
+ _ioSession.close();
+ }
+ }
+
+ public void flush()
+ {
+ if (_lastWriteFuture != null)
+ {
+ _lastWriteFuture.join();
+ }
+ }
+
+ public void send(ByteBuffer msg)
+ {
+ org.apache.mina.common.ByteBuffer minaBuf = org.apache.mina.common.ByteBuffer.allocate(msg.capacity());
+ minaBuf.put(msg);
+ minaBuf.flip();
+ _lastWriteFuture = _ioSession.write(minaBuf);
+ }
+
+ public void setIdleTimeout(int i)
+ {
+ // MINA doesn't support setting SO_TIMEOUT
+ }
+
+ public void exceptionCaught(IoSession protocolSession, Throwable throwable) throws Exception
+ {
+ if (_protocolEngine != null)
+ {
+ _protocolEngine.exception(throwable);
+ }
+ else
+ {
+ _logger.error("Exception thrown and no ProtocolEngine to handle it", throwable);
+ }
+ _lastException = throwable;
+ }
+
+ /**
+ * Invoked when a message is received on a particular protocol session. Note
+ * that a protocol session is directly tied to a particular physical
+ * connection.
+ *
+ * @param protocolSession
+ * the protocol session that received the message
+ * @param message
+ * the message itself (i.e. a decoded frame)
+ *
+ * @throws Exception
+ * if the message cannot be processed
+ */
+ public void messageReceived(IoSession protocolSession, Object message) throws Exception
+ {
+ if (message instanceof org.apache.mina.common.ByteBuffer)
+ {
+ ((ProtocolEngine) protocolSession.getAttachment()).received(((org.apache.mina.common.ByteBuffer) message).buf());
+ }
+ else
+ {
+ throw new IllegalStateException("Handed unhandled message. message.class = " + message.getClass() + " message = " + message);
+ }
+ }
+
+ public void sessionClosed(IoSession protocolSession) throws Exception
+ {
+ ((ProtocolEngine) protocolSession.getAttachment()).closed();
+ }
+
+ public void sessionCreated(IoSession protocolSession) throws Exception
+ {
+ // Configure the session with SSL if necessary
+ SessionUtil.initialize(protocolSession);
+ if (_executorPool)
+ {
+ if (_sslFactory != null)
+ {
+ protocolSession.getFilterChain().addAfter("AsynchronousReadFilter", "sslFilter",
+ new SSLFilter(_sslFactory.buildServerContext()));
+ }
+ }
+ else
+ {
+ if (_sslFactory != null)
+ {
+ protocolSession.getFilterChain().addBefore("protocolFilter", "sslFilter",
+ new SSLFilter(_sslFactory.buildServerContext()));
+ }
+ }
+ // Do we want to have read/write buffer limits?
+ if (_protectIO)
+ {
+ //Add IO Protection Filters
+ IoFilterChain chain = protocolSession.getFilterChain();
+
+ protocolSession.getFilterChain().addLast("tempExecutorFilterForFilterBuilder", new ExecutorFilter());
+
+ ReadThrottleFilterBuilder readfilter = new ReadThrottleFilterBuilder();
+ readfilter.setMaximumConnectionBufferSize(_config.getReceiveBufferSize());
+ readfilter.attach(chain);
+
+ WriteBufferLimitFilterBuilder writefilter = new WriteBufferLimitFilterBuilder();
+ writefilter.setMaximumConnectionBufferSize(_config.getSendBufferSize());
+ writefilter.attach(chain);
+
+ protocolSession.getFilterChain().remove("tempExecutorFilterForFilterBuilder");
+ }
+
+ if (_ioSession == null)
+ {
+ _ioSession = protocolSession;
+ }
+
+ if (_acceptingConnections)
+ {
+ // Set up the protocol engine
+ ProtocolEngine protocolEngine = _factory.newProtocolEngine(this);
+ MINANetworkDriver newDriver = new MINANetworkDriver(_useNIO, _processors, _executorPool, _protectIO, protocolEngine, protocolSession);
+ protocolEngine.setNetworkDriver(newDriver);
+ }
+ }
+
+ public void sessionIdle(IoSession session, IdleStatus status) throws Exception
+ {
+ if (IdleStatus.WRITER_IDLE.equals(status))
+ {
+ ((ProtocolEngine) session.getAttachment()).writerIdle();
+ }
+ else if (IdleStatus.READER_IDLE.equals(status))
+ {
+ ((ProtocolEngine) session.getAttachment()).readerIdle();
+ }
+ }
+
+ private ProtocolEngine getProtocolEngine()
+ {
+ return _protocolEngine;
+ }
+
+ public void setProtocolEngineFactory(ProtocolEngineFactory engineFactory, boolean acceptingConnections)
+ {
+ _factory = engineFactory;
+ _acceptingConnections = acceptingConnections;
+ }
+
+ public void setProtocolEngine(ProtocolEngine protocolEngine)
+ {
+ _protocolEngine = protocolEngine;
+ if (_ioSession != null)
+ {
+ _ioSession.setAttachment(protocolEngine);
+ }
+ }
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaHandler.java b/java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaHandler.java
new file mode 100644
index 0000000000..b89eed48b0
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaHandler.java
@@ -0,0 +1,274 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.transport.network.mina;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+
+import org.apache.mina.common.*;
+
+import org.apache.mina.transport.socket.nio.SocketAcceptor;
+import org.apache.mina.transport.socket.nio.SocketSessionConfig;
+import org.apache.mina.transport.socket.nio.SocketConnector;
+import org.apache.mina.filter.ReadThrottleFilterBuilder;
+import org.apache.mina.filter.WriteBufferLimitFilterBuilder;
+import org.apache.mina.filter.executor.ExecutorFilter;
+
+import org.apache.qpid.transport.Binding;
+import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.ConnectionDelegate;
+import org.apache.qpid.transport.Receiver;
+import org.apache.qpid.transport.Sender;
+import org.apache.qpid.transport.network.ConnectionBinding;
+
+import org.apache.qpid.transport.util.Logger;
+
+import org.apache.qpid.transport.network.Assembler;
+import org.apache.qpid.transport.network.Disassembler;
+import org.apache.qpid.transport.network.InputHandler;
+
+import static org.apache.qpid.transport.util.Functions.*;
+
+/**
+ * MinaHandler
+ *
+ * @author Rafael H. Schloming
+ */
+//RA making this public until we sort out the package issues
+public class MinaHandler<E> implements IoHandler
+{
+ /** Default buffer size for pending messages reads */
+ private static final String DEFAULT_READ_BUFFER_LIMIT = "262144";
+ /** Default buffer size for pending messages writes */
+ private static final String DEFAULT_WRITE_BUFFER_LIMIT = "262144";
+ private static final int MAX_RCVBUF = 64*1024;
+
+ private static final Logger log = Logger.get(MinaHandler.class);
+
+ static
+ {
+ ByteBuffer.setAllocator(new SimpleByteBufferAllocator());
+ ByteBuffer.setUseDirectBuffers(Boolean.getBoolean("amqj.enableDirectBuffers"));
+ }
+
+ private final Binding<E,java.nio.ByteBuffer> binding;
+
+ private MinaHandler(Binding<E,java.nio.ByteBuffer> binding)
+ {
+ this.binding = binding;
+ }
+
+ public void messageReceived(IoSession ssn, Object obj)
+ {
+ Attachment<E> attachment = (Attachment<E>) ssn.getAttachment();
+ ByteBuffer buf = (ByteBuffer) obj;
+ try
+ {
+ attachment.receiver.received(buf.buf());
+ }
+ catch (Throwable t)
+ {
+ log.error(t, "exception handling buffer %s", str(buf.buf()));
+ throw new RuntimeException(t);
+ }
+ }
+
+ public void messageSent(IoSession ssn, Object obj)
+ {
+ // do nothing
+ }
+
+ public void exceptionCaught(IoSession ssn, Throwable e)
+ {
+ Attachment<E> attachment = (Attachment<E>) ssn.getAttachment();
+ attachment.receiver.exception(e);
+ }
+
+ /**
+ * Invoked by MINA when a MINA session for a new connection is created. This method sets up the filter chain on the
+ * session, which filters the events handled by this handler. The filter chain consists of, handing off events
+ * to an optional protectio
+ *
+ * @param session The MINA session.
+ * @throws Exception Any underlying exceptions are allowed to fall through to MINA.
+ */
+ public void sessionCreated(IoSession session) throws Exception
+ {
+ log.debug("Protocol session created for session " + System.identityHashCode(session));
+
+ if (Boolean.getBoolean("protectio"))
+ {
+ try
+ {
+ //Add IO Protection Filters
+ IoFilterChain chain = session.getFilterChain();
+
+ session.getFilterChain().addLast("tempExecutorFilterForFilterBuilder", new ExecutorFilter());
+
+ ReadThrottleFilterBuilder readfilter = new ReadThrottleFilterBuilder();
+ readfilter.setMaximumConnectionBufferSize(
+ Integer.parseInt(System.getProperty("qpid.read.buffer.limit", DEFAULT_READ_BUFFER_LIMIT)));
+ readfilter.attach(chain);
+
+ WriteBufferLimitFilterBuilder writefilter = new WriteBufferLimitFilterBuilder();
+ writefilter.setMaximumConnectionBufferSize(
+ Integer.parseInt(System.getProperty("qpid.write.buffer.limit", DEFAULT_WRITE_BUFFER_LIMIT)));
+ writefilter.attach(chain);
+ session.getFilterChain().remove("tempExecutorFilterForFilterBuilder");
+
+ log.info("Using IO Read/Write Filter Protection");
+ }
+ catch (Exception e)
+ {
+ log.error("Unable to attach IO Read/Write Filter Protection :" + e.getMessage());
+ }
+ }
+ }
+
+ public void sessionOpened(final IoSession ssn)
+ {
+ log.debug("opened: %s", this);
+ E endpoint = binding.endpoint(new MinaSender(ssn));
+ Attachment<E> attachment =
+ new Attachment<E>(endpoint, binding.receiver(endpoint));
+
+ // We need to synchronize and notify here because the MINA
+ // connect future returns the session prior to the attachment
+ // being set. This is arguably a bug in MINA.
+ synchronized (ssn)
+ {
+ ssn.setAttachment(attachment);
+ ssn.notifyAll();
+ }
+ }
+
+ public void sessionClosed(IoSession ssn)
+ {
+ log.debug("closed: %s", ssn);
+ Attachment<E> attachment = (Attachment<E>) ssn.getAttachment();
+ attachment.receiver.closed();
+ ssn.setAttachment(null);
+ }
+
+ public void sessionIdle(IoSession ssn, IdleStatus status)
+ {
+ // do nothing
+ }
+
+ private static class Attachment<E>
+ {
+
+ E endpoint;
+ Receiver<java.nio.ByteBuffer> receiver;
+
+ Attachment(E endpoint, Receiver<java.nio.ByteBuffer> receiver)
+ {
+ this.endpoint = endpoint;
+ this.receiver = receiver;
+ }
+ }
+
+ public static final void accept(String host, int port,
+ Binding<?,java.nio.ByteBuffer> binding)
+ throws IOException
+ {
+ accept(new InetSocketAddress(host, port), binding);
+ }
+
+ public static final <E> void accept(SocketAddress address,
+ Binding<E,java.nio.ByteBuffer> binding)
+ throws IOException
+ {
+ IoAcceptor acceptor = new SocketAcceptor();
+ acceptor.bind(address, new MinaHandler<E>(binding));
+ }
+
+ public static final <E> E connect(String host, int port,
+ Binding<E,java.nio.ByteBuffer> binding)
+ {
+ return connect(new InetSocketAddress(host, port), binding);
+ }
+
+ public static final <E> E connect(SocketAddress address,
+ Binding<E,java.nio.ByteBuffer> binding)
+ {
+ MinaHandler<E> handler = new MinaHandler<E>(binding);
+ SocketConnector connector = new SocketConnector();
+ IoServiceConfig acceptorConfig = connector.getDefaultConfig();
+ acceptorConfig.setThreadModel(ThreadModel.MANUAL);
+ SocketSessionConfig scfg = (SocketSessionConfig) acceptorConfig.getSessionConfig();
+ scfg.setTcpNoDelay(Boolean.getBoolean("amqj.tcpNoDelay"));
+ Integer sendBufferSize = Integer.getInteger("amqj.sendBufferSize");
+ if (sendBufferSize != null && sendBufferSize > 0)
+ {
+ scfg.setSendBufferSize(sendBufferSize);
+ }
+ Integer receiveBufferSize = Integer.getInteger("amqj.receiveBufferSize");
+ if (receiveBufferSize != null && receiveBufferSize > 0)
+ {
+ scfg.setReceiveBufferSize(receiveBufferSize);
+ }
+ else if (scfg.getReceiveBufferSize() > MAX_RCVBUF)
+ {
+ scfg.setReceiveBufferSize(MAX_RCVBUF);
+ }
+ connector.setWorkerTimeout(0);
+ ConnectFuture cf = connector.connect(address, handler);
+ cf.join();
+ IoSession ssn = cf.getSession();
+
+ // We need to synchronize and wait here because the MINA
+ // connect future returns the session prior to the attachment
+ // being set. This is arguably a bug in MINA.
+ synchronized (ssn)
+ {
+ while (ssn.getAttachment() == null)
+ {
+ try
+ {
+ ssn.wait();
+ }
+ catch (InterruptedException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ Attachment<E> attachment = (Attachment<E>) ssn.getAttachment();
+ return attachment.endpoint;
+ }
+
+ public static final void accept(String host, int port,
+ ConnectionDelegate delegate)
+ throws IOException
+ {
+ accept(host, port, ConnectionBinding.get(delegate));
+ }
+
+ public static final Connection connect(String host, int port,
+ ConnectionDelegate delegate)
+ {
+ return connect(host, port, ConnectionBinding.get(delegate));
+ }
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaSender.java b/java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaSender.java
new file mode 100644
index 0000000000..22b9c5e784
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaSender.java
@@ -0,0 +1,90 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.transport.network.mina;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.CloseFuture;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.common.WriteFuture;
+import org.apache.qpid.transport.Sender;
+import org.apache.qpid.transport.TransportException;
+
+
+/**
+ * MinaSender
+ */
+
+public class MinaSender implements Sender<java.nio.ByteBuffer>
+{
+ private static final int TIMEOUT = 2 * 60 * 1000;
+
+ private final IoSession session;
+ private WriteFuture lastWrite = null;
+
+ public MinaSender(IoSession session)
+ {
+ this.session = session;
+ }
+
+ public void send(java.nio.ByteBuffer buf)
+ {
+ if (session.isClosing())
+ {
+ throw new TransportException("attempted to write to a closed socket");
+ }
+
+ synchronized (this)
+ {
+ lastWrite = session.write(ByteBuffer.wrap(buf));
+ }
+ }
+
+ public void flush()
+ {
+ // pass
+ }
+
+ public synchronized void close()
+ {
+ // MINA will sometimes throw away in-progress writes when you
+ // ask it to close
+ synchronized (this)
+ {
+ if (lastWrite != null)
+ {
+ lastWrite.join();
+ }
+ }
+ CloseFuture closed = session.close();
+ closed.join();
+ }
+
+ public void setIdleTimeout(int i)
+ {
+ //noop
+ }
+
+ public long getIdleTimeout()
+ {
+ return 0;
+ }
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/nio/NioHandler.java b/java/common/src/main/java/org/apache/qpid/transport/network/nio/NioHandler.java
new file mode 100644
index 0000000000..84e66c25bd
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/nio/NioHandler.java
@@ -0,0 +1,135 @@
+package org.apache.qpid.transport.network.nio;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.ConnectionDelegate;
+import org.apache.qpid.transport.Receiver;
+import org.apache.qpid.transport.network.Assembler;
+import org.apache.qpid.transport.network.Disassembler;
+import org.apache.qpid.transport.network.InputHandler;
+
+public class NioHandler implements Runnable
+{
+ private Receiver<ByteBuffer> _receiver;
+ private SocketChannel _ch;
+ private ByteBuffer _readBuf;
+ private static Map<Long,NioSender> _handlers = new ConcurrentHashMap<Long,NioSender>();
+
+ private NioHandler(){}
+
+ public static final Connection connect(String host, int port,
+ ConnectionDelegate delegate)
+ {
+ NioHandler handler = new NioHandler();
+ return handler.connectInternal(host,port,delegate);
+ }
+
+ private Connection connectInternal(String host, int port,
+ ConnectionDelegate delegate)
+ {
+ try
+ {
+ SocketAddress address = new InetSocketAddress(host,port);
+ _ch = SocketChannel.open();
+ _ch.socket().setReuseAddress(true);
+ _ch.configureBlocking(true);
+ _ch.socket().setTcpNoDelay(true);
+ if (address != null)
+ {
+ _ch.socket().connect(address);
+ }
+ while (_ch.isConnectionPending())
+ {
+
+ }
+
+ }
+ catch (SocketException e)
+ {
+
+ e.printStackTrace();
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ }
+
+ NioSender sender = new NioSender(_ch);
+ Connection con = new Connection();
+ con.setSender(new Disassembler(sender, 64*1024 - 1));
+ con.setConnectionDelegate(delegate);
+
+ _handlers.put(con.getConnectionId(),sender);
+
+ _receiver = new InputHandler(new Assembler(con), InputHandler.State.FRAME_HDR);
+
+ Thread t = new Thread(this);
+ t.start();
+
+ return con;
+ }
+
+ public void run()
+ {
+ _readBuf = ByteBuffer.allocate(512);
+ long read = 0;
+ while(_ch.isConnected() && _ch.isOpen())
+ {
+ try
+ {
+ read = _ch.read(_readBuf);
+ if (read > 0)
+ {
+ _readBuf.flip();
+ ByteBuffer b = ByteBuffer.allocate(_readBuf.remaining());
+ b.put(_readBuf);
+ b.flip();
+ _readBuf.clear();
+ _receiver.received(b);
+ }
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+
+ //throw new EOFException("The underlying socket/channel has closed");
+ }
+
+ public static void startBatchingFrames(int connectionId)
+ {
+ NioSender sender = _handlers.get(connectionId);
+ sender.setStartBatching();
+ }
+
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/nio/NioSender.java b/java/common/src/main/java/org/apache/qpid/transport/network/nio/NioSender.java
new file mode 100644
index 0000000000..2fa875f279
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/nio/NioSender.java
@@ -0,0 +1,126 @@
+package org.apache.qpid.transport.network.nio;
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+
+import java.nio.ByteBuffer;
+import java.nio.channels.SocketChannel;
+
+import org.apache.qpid.transport.Sender;
+
+public class NioSender implements Sender<java.nio.ByteBuffer>
+{
+ private final Object lock = new Object();
+ private SocketChannel _ch;
+ private boolean _batch = false;
+ private ByteBuffer _batcher;
+
+ public NioSender(SocketChannel ch)
+ {
+ this._ch = ch;
+ }
+
+ public void send(java.nio.ByteBuffer buf)
+ {
+ if (_batch)
+ {
+ //System.out.println(_batcher.position() + " , " + buf.remaining() + " , " + buf.position() + ","+_batcher.capacity());
+ if (_batcher.position() + buf.remaining() >= _batcher.capacity())
+ {
+ _batcher.flip();
+ write(_batcher);
+ _batcher.clear();
+ if (buf.remaining() > _batcher.capacity())
+ {
+ write(buf);
+ }
+ else
+ {
+ _batcher.put(buf);
+ }
+ }
+ else
+ {
+ _batcher.put(buf);
+ }
+ }
+ else
+ {
+ write(buf);
+ }
+ }
+
+ public void flush()
+ {
+ // pass
+ }
+
+ private void write(java.nio.ByteBuffer buf)
+ {
+ synchronized (lock)
+ {
+ if( _ch.isConnected() && _ch.isOpen())
+ {
+ try
+ {
+ _ch.write(buf);
+ }
+ catch(Exception e)
+ {
+ e.fillInStackTrace();
+ }
+ }
+ else
+ {
+ throw new RuntimeException("Trying to write on a closed socket");
+ }
+
+ }
+ }
+
+ public void setStartBatching()
+ {
+ _batch = true;
+ _batcher = ByteBuffer.allocate(1024);
+ }
+
+ public void close()
+ {
+ // MINA will sometimes throw away in-progress writes when you
+ // ask it to close
+ synchronized (lock)
+ {
+ try
+ {
+ _ch.close();
+ }
+ catch(Exception e)
+ {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ public void setIdleTimeout(int i)
+ {
+ //noop
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/security/SSLStatus.java b/java/common/src/main/java/org/apache/qpid/transport/network/security/SSLStatus.java
deleted file mode 100644
index 9db7dd557a..0000000000
--- a/java/common/src/main/java/org/apache/qpid/transport/network/security/SSLStatus.java
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-
-package org.apache.qpid.transport.network.security;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-
-public class SSLStatus
-{
- private final Object _sslLock = new Object();
- private final AtomicBoolean _sslErrorFlag = new AtomicBoolean(false);
-
- /**
- * Lock used to coordinate the SSL sender with the SSL receiver.
- *
- * @return lock
- */
- public Object getSslLock()
- {
- return _sslLock;
- }
-
- public boolean getSslErrorFlag()
- {
- return _sslErrorFlag.get();
- }
-
- public void setSslErrorFlag()
- {
- _sslErrorFlag.set(true);
- }
-}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayer.java b/java/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayer.java
index 9fd65c6e51..3f0966903d 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayer.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayer.java
@@ -25,8 +25,8 @@ import java.nio.ByteBuffer;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLEngine;
-import org.apache.qpid.ssl.SSLContextFactory;
import org.apache.qpid.transport.Connection;
+import org.apache.qpid.transport.ConnectionListener;
import org.apache.qpid.transport.ConnectionSettings;
import org.apache.qpid.transport.Receiver;
import org.apache.qpid.transport.Sender;
@@ -37,12 +37,149 @@ import org.apache.qpid.transport.network.security.ssl.SSLReceiver;
import org.apache.qpid.transport.network.security.ssl.SSLSender;
import org.apache.qpid.transport.network.security.ssl.SSLUtil;
-public interface SecurityLayer
+public class SecurityLayer
{
-
- public Sender<ByteBuffer> sender(Sender<ByteBuffer> delegate);
- public Receiver<ByteBuffer> receiver(Receiver<ByteBuffer> delegate);
- public String getUserID();
-
+ ConnectionSettings settings;
+ Connection con;
+ SSLSecurityLayer sslLayer;
+ SASLSecurityLayer saslLayer;
+
+ public void init(Connection con) throws TransportException
+ {
+ this.con = con;
+ this.settings = con.getConnectionSettings();
+ if (settings.isUseSSL())
+ {
+ sslLayer = new SSLSecurityLayer();
+ }
+ if (settings.isUseSASLEncryption())
+ {
+ saslLayer = new SASLSecurityLayer();
+ }
+
+ }
+
+ public Sender<ByteBuffer> sender(Sender<ByteBuffer> delegate)
+ {
+ Sender<ByteBuffer> sender = delegate;
+
+ if (settings.isUseSSL())
+ {
+ sender = sslLayer.sender(sender);
+ }
+
+ if (settings.isUseSASLEncryption())
+ {
+ sender = saslLayer.sender(sender);
+ }
+
+ return sender;
+ }
+
+ public Receiver<ByteBuffer> receiver(Receiver<ByteBuffer> delegate)
+ {
+ Receiver<ByteBuffer> receiver = delegate;
+
+ if (settings.isUseSSL())
+ {
+ receiver = sslLayer.receiver(receiver);
+ }
+
+ if (settings.isUseSASLEncryption())
+ {
+ receiver = saslLayer.receiver(receiver);
+ }
+
+ return receiver;
+ }
+
+ public String getUserID()
+ {
+ if (settings.isUseSSL())
+ {
+ return sslLayer.getUserID();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ class SSLSecurityLayer
+ {
+ SSLEngine engine;
+ SSLSender sender;
+
+ public SSLSecurityLayer()
+ {
+ SSLContext sslCtx;
+ try
+ {
+ sslCtx = SSLUtil.createSSLContext(settings);
+ }
+ catch (Exception e)
+ {
+ throw new TransportException("Error creating SSL Context", e);
+ }
+
+ try
+ {
+ engine = sslCtx.createSSLEngine();
+ engine.setUseClientMode(true);
+ }
+ catch(Exception e)
+ {
+ throw new TransportException("Error creating SSL Engine", e);
+ }
+ }
+
+ public SSLSender sender(Sender<ByteBuffer> delegate)
+ {
+ sender = new SSLSender(engine,delegate);
+ sender.setConnectionSettings(settings);
+ return sender;
+ }
+
+ public SSLReceiver receiver(Receiver<ByteBuffer> delegate)
+ {
+ if (sender == null)
+ {
+ throw new
+ IllegalStateException("SecurityLayer.sender method should be " +
+ "invoked before SecurityLayer.receiver");
+ }
+
+ SSLReceiver receiver = new SSLReceiver(engine,delegate,sender);
+ receiver.setConnectionSettings(settings);
+ return receiver;
+ }
+
+ public String getUserID()
+ {
+ return SSLUtil.retriveIdentity(engine);
+ }
+
+ }
+
+ class SASLSecurityLayer
+ {
+ public SASLSecurityLayer()
+ {
+ }
+
+ public SASLSender sender(Sender<ByteBuffer> delegate)
+ {
+ SASLSender sender = new SASLSender(delegate);
+ con.addConnectionListener((ConnectionListener)sender);
+ return sender;
+ }
+
+ public SASLReceiver receiver(Receiver<ByteBuffer> delegate)
+ {
+ SASLReceiver receiver = new SASLReceiver(delegate);
+ con.addConnectionListener((ConnectionListener)receiver);
+ return receiver;
+ }
+
+ }
}
-
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayerFactory.java b/java/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayerFactory.java
deleted file mode 100644
index 17f89c34ef..0000000000
--- a/java/common/src/main/java/org/apache/qpid/transport/network/security/SecurityLayerFactory.java
+++ /dev/null
@@ -1,161 +0,0 @@
-package org.apache.qpid.transport.network.security;
-
-import org.apache.qpid.ssl.SSLContextFactory;
-import org.apache.qpid.transport.*;
-import org.apache.qpid.transport.network.security.sasl.SASLReceiver;
-import org.apache.qpid.transport.network.security.sasl.SASLSender;
-import org.apache.qpid.transport.network.security.ssl.SSLReceiver;
-import org.apache.qpid.transport.network.security.ssl.SSLSender;
-import org.apache.qpid.transport.network.security.ssl.SSLUtil;
-
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLEngine;
-import java.nio.ByteBuffer;
-
-public class SecurityLayerFactory
-{
- public static SecurityLayer newInstance(ConnectionSettings settings)
- {
-
- SecurityLayer layer = NullSecurityLayer.getInstance();
-
- if (settings.isUseSSL())
- {
- layer = new SSLSecurityLayer(settings, layer);
- }
- if (settings.isUseSASLEncryption())
- {
- layer = new SASLSecurityLayer(layer);
- }
-
- return layer;
-
- }
-
- static class SSLSecurityLayer implements SecurityLayer
- {
-
- private final SSLEngine _engine;
- private final SSLStatus _sslStatus = new SSLStatus();
- private String _hostname;
- private SecurityLayer _layer;
-
-
- public SSLSecurityLayer(ConnectionSettings settings, SecurityLayer layer)
- {
-
- SSLContext sslCtx;
- _layer = layer;
- try
- {
- sslCtx = SSLContextFactory
- .buildClientContext(settings.getTrustStorePath(),
- settings.getTrustStorePassword(),
- settings.getTrustStoreCertType(),
- settings.getKeyStorePath(),
- settings.getKeyStorePassword(),
- settings.getKeyStoreCertType(),
- settings.getCertAlias());
- }
- catch (Exception e)
- {
- throw new TransportException("Error creating SSL Context", e);
- }
-
- if(settings.isVerifyHostname())
- {
- _hostname = settings.getHost();
- }
-
- try
- {
- _engine = sslCtx.createSSLEngine();
- _engine.setUseClientMode(true);
- }
- catch(Exception e)
- {
- throw new TransportException("Error creating SSL Engine", e);
- }
-
- }
-
- public Sender<ByteBuffer> sender(Sender<ByteBuffer> delegate)
- {
- SSLSender sender = new SSLSender(_engine, _layer.sender(delegate), _sslStatus);
- sender.setHostname(_hostname);
- return sender;
- }
-
- public Receiver<ByteBuffer> receiver(Receiver<ByteBuffer> delegate)
- {
- SSLReceiver receiver = new SSLReceiver(_engine, _layer.receiver(delegate), _sslStatus);
- receiver.setHostname(_hostname);
- return receiver;
- }
-
- public String getUserID()
- {
- return SSLUtil.retriveIdentity(_engine);
- }
- }
-
-
- static class SASLSecurityLayer implements SecurityLayer
- {
-
- private SecurityLayer _layer;
-
- SASLSecurityLayer(SecurityLayer layer)
- {
- _layer = layer;
- }
-
- public SASLSender sender(Sender<ByteBuffer> delegate)
- {
- SASLSender sender = new SASLSender(_layer.sender(delegate));
- return sender;
- }
-
- public SASLReceiver receiver(Receiver<ByteBuffer> delegate)
- {
- SASLReceiver receiver = new SASLReceiver(_layer.receiver(delegate));
- return receiver;
- }
-
- public String getUserID()
- {
- return _layer.getUserID();
- }
- }
-
-
- static class NullSecurityLayer implements SecurityLayer
- {
-
- private static final NullSecurityLayer INSTANCE = new NullSecurityLayer();
-
- private NullSecurityLayer()
- {
- }
-
- public Sender<ByteBuffer> sender(Sender<ByteBuffer> delegate)
- {
- return delegate;
- }
-
- public Receiver<ByteBuffer> receiver(Receiver<ByteBuffer> delegate)
- {
- return delegate;
- }
-
- public String getUserID()
- {
- return null;
- }
-
- public static NullSecurityLayer getInstance()
- {
- return INSTANCE;
- }
- }
-}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/security/sasl/SASLSender.java b/java/common/src/main/java/org/apache/qpid/transport/network/security/sasl/SASLSender.java
index 2d9e4e9a7e..27255f79f6 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/security/sasl/SASLSender.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/security/sasl/SASLSender.java
@@ -43,7 +43,8 @@ public class SASLSender extends SASLEncryptor implements Sender<ByteBuffer> {
this.delegate = delegate;
log.debug("SASL Sender enabled");
}
-
+
+ @Override
public void close()
{
@@ -64,11 +65,13 @@ public class SASLSender extends SASLEncryptor implements Sender<ByteBuffer> {
}
}
+ @Override
public void flush()
{
delegate.flush();
}
+ @Override
public void send(ByteBuffer buf)
{
if (closed.get())
@@ -105,6 +108,7 @@ public class SASLSender extends SASLEncryptor implements Sender<ByteBuffer> {
}
}
+ @Override
public void setIdleTimeout(int i)
{
delegate.setIdleTimeout(i);
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/QpidClientX509KeyManager.java b/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/QpidClientX509KeyManager.java
index 4391e8adfc..14f28f8828 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/QpidClientX509KeyManager.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/QpidClientX509KeyManager.java
@@ -20,9 +20,7 @@
*/
package org.apache.qpid.transport.network.security.ssl;
-import java.io.IOException;
import java.net.Socket;
-import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.Principal;
import java.security.PrivateKey;
@@ -42,7 +40,7 @@ public class QpidClientX509KeyManager extends X509ExtendedKeyManager
String alias;
public QpidClientX509KeyManager(String alias, String keyStorePath,
- String keyStorePassword,String keyStoreCertType) throws GeneralSecurityException, IOException
+ String keyStorePassword,String keyStoreCertType) throws Exception
{
this.alias = alias;
KeyStore ks = SSLUtil.getInitializedKeyStore(keyStorePath,keyStorePassword);
@@ -50,45 +48,51 @@ public class QpidClientX509KeyManager extends X509ExtendedKeyManager
kmf.init(ks, keyStorePassword.toCharArray());
this.delegate = (X509ExtendedKeyManager)kmf.getKeyManagers()[0];
}
-
+
+ @Override
public String chooseClientAlias(String[] keyType, Principal[] issuers, Socket socket)
{
log.debug("chooseClientAlias:Returning alias " + alias);
return alias;
}
+ @Override
public String chooseServerAlias(String keyType, Principal[] issuers, Socket socket)
{
return delegate.chooseServerAlias(keyType, issuers, socket);
}
+ @Override
public X509Certificate[] getCertificateChain(String alias)
{
return delegate.getCertificateChain(alias);
}
+ @Override
public String[] getClientAliases(String keyType, Principal[] issuers)
{
log.debug("getClientAliases:Returning alias " + alias);
return new String[]{alias};
}
+ @Override
public PrivateKey getPrivateKey(String alias)
{
return delegate.getPrivateKey(alias);
}
+ @Override
public String[] getServerAliases(String keyType, Principal[] issuers)
{
return delegate.getServerAliases(keyType, issuers);
}
-
+
public String chooseEngineClientAlias(String[] keyType, Principal[] issuers, SSLEngine engine)
{
log.debug("chooseEngineClientAlias:Returning alias " + alias);
return alias;
}
-
+
public String chooseEngineServerAlias(String keyType, Principal[] issuers, SSLEngine engine)
{
return delegate.chooseEngineServerAlias(keyType, issuers, engine);
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLReceiver.java b/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLReceiver.java
index 8ad40bbfd3..e227a51729 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLReceiver.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLReceiver.java
@@ -24,43 +24,43 @@ import java.nio.ByteBuffer;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
import javax.net.ssl.SSLEngineResult.Status;
-import javax.net.ssl.SSLException;
import org.apache.qpid.transport.ConnectionSettings;
import org.apache.qpid.transport.Receiver;
import org.apache.qpid.transport.TransportException;
-import org.apache.qpid.transport.network.security.SSLStatus;
import org.apache.qpid.transport.util.Logger;
public class SSLReceiver implements Receiver<ByteBuffer>
{
- private static final Logger log = Logger.get(SSLReceiver.class);
-
- private final Receiver<ByteBuffer> delegate;
- private final SSLEngine engine;
- private final int sslBufSize;
- private final ByteBuffer localBuffer;
- private final SSLStatus _sslStatus;
+ private Receiver<ByteBuffer> delegate;
+ private SSLEngine engine;
+ private SSLSender sender;
+ private int sslBufSize;
private ByteBuffer appData;
+ private ByteBuffer localBuffer;
private boolean dataCached = false;
+ private final Object notificationToken;
+ private ConnectionSettings settings;
+
+ private static final Logger log = Logger.get(SSLReceiver.class);
- private String _hostname;
-
- public SSLReceiver(final SSLEngine engine, final Receiver<ByteBuffer> delegate, final SSLStatus sslStatus)
+ public SSLReceiver(SSLEngine engine, Receiver<ByteBuffer> delegate,SSLSender sender)
{
this.engine = engine;
this.delegate = delegate;
+ this.sender = sender;
this.sslBufSize = engine.getSession().getApplicationBufferSize();
appData = ByteBuffer.allocate(sslBufSize);
localBuffer = ByteBuffer.allocate(sslBufSize);
- _sslStatus = sslStatus;
+ notificationToken = sender.getNotificationToken();
}
- public void setHostname(String hostname)
+ public void setConnectionSettings(ConnectionSettings settings)
{
- _hostname = hostname;
+ this.settings = settings;
}
public void closed()
@@ -102,9 +102,9 @@ public class SSLReceiver implements Receiver<ByteBuffer>
try
{
SSLEngineResult result = engine.unwrap(netData, appData);
- synchronized (_sslStatus.getSslLock())
+ synchronized (notificationToken)
{
- _sslStatus.getSslLock().notifyAll();
+ notificationToken.notifyAll();
}
int read = result.bytesProduced();
@@ -129,9 +129,9 @@ public class SSLReceiver implements Receiver<ByteBuffer>
switch(status)
{
case CLOSED:
- synchronized(_sslStatus.getSslLock())
+ synchronized(notificationToken)
{
- _sslStatus.getSslLock().notifyAll();
+ notificationToken.notifyAll();
}
return;
@@ -163,20 +163,20 @@ public class SSLReceiver implements Receiver<ByteBuffer>
break;
case NEED_TASK:
- doTasks();
+ sender.doTasks();
handshakeStatus = engine.getHandshakeStatus();
case FINISHED:
- if (_hostname != null)
+ if (this.settings != null && this.settings.isVerifyHostname() )
{
- SSLUtil.verifyHostname(engine, _hostname);
+ SSLUtil.verifyHostname(engine, this.settings.getHost());
}
case NEED_WRAP:
case NOT_HANDSHAKING:
- synchronized(_sslStatus.getSslLock())
+ synchronized(notificationToken)
{
- _sslStatus.getSslLock().notifyAll();
+ notificationToken.notifyAll();
}
break;
@@ -189,23 +189,14 @@ public class SSLReceiver implements Receiver<ByteBuffer>
catch(SSLException e)
{
log.error(e, "Error caught in SSLReceiver");
- _sslStatus.setSslErrorFlag();
- synchronized(_sslStatus.getSslLock())
+ sender.setErrorFlag();
+ synchronized(notificationToken)
{
- _sslStatus.getSslLock().notifyAll();
+ notificationToken.notifyAll();
}
exception(new TransportException("Error in SSLReceiver",e));
}
}
}
-
- private void doTasks()
- {
- Runnable runnable;
- while ((runnable = engine.getDelegatedTask()) != null) {
- runnable.run();
- }
- }
-
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLSender.java b/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLSender.java
index 6f5aa6d86e..cd47a11825 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLSender.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLSender.java
@@ -31,38 +31,35 @@ import javax.net.ssl.SSLEngineResult.Status;
import org.apache.qpid.transport.ConnectionSettings;
import org.apache.qpid.transport.Sender;
import org.apache.qpid.transport.SenderException;
-import org.apache.qpid.transport.network.security.SSLStatus;
import org.apache.qpid.transport.util.Logger;
public class SSLSender implements Sender<ByteBuffer>
{
- private static final Logger log = Logger.get(SSLSender.class);
-
- private final Sender<ByteBuffer> delegate;
- private final SSLEngine engine;
- private final int sslBufSize;
- private final ByteBuffer netData;
- private final long timeout;
- private final SSLStatus _sslStatus;
-
- private String _hostname;
-
+ private Sender<ByteBuffer> delegate;
+ private SSLEngine engine;
+ private int sslBufSize;
+ private ByteBuffer netData;
+ private long timeout = 30000;
+ private ConnectionSettings settings;
+
+ private final Object engineState = new Object();
private final AtomicBoolean closed = new AtomicBoolean(false);
+ private final AtomicBoolean error = new AtomicBoolean(false);
+ private static final Logger log = Logger.get(SSLSender.class);
- public SSLSender(SSLEngine engine, Sender<ByteBuffer> delegate, SSLStatus sslStatus)
+ public SSLSender(SSLEngine engine, Sender<ByteBuffer> delegate)
{
this.engine = engine;
this.delegate = delegate;
sslBufSize = engine.getSession().getPacketBufferSize();
netData = ByteBuffer.allocate(sslBufSize);
timeout = Long.getLong("qpid.ssl_timeout", 60000);
- _sslStatus = sslStatus;
}
- public void setHostname(String hostname)
+ public void setConnectionSettings(ConnectionSettings settings)
{
- _hostname = hostname;
+ this.settings = settings;
}
public void close()
@@ -86,13 +83,13 @@ public class SSLSender implements Sender<ByteBuffer>
}
- synchronized(_sslStatus.getSslLock())
+ synchronized(engineState)
{
while (!engine.isOutboundDone())
{
try
{
- _sslStatus.getSslLock().wait();
+ engineState.wait();
}
catch(InterruptedException e)
{
@@ -151,7 +148,7 @@ public class SSLSender implements Sender<ByteBuffer>
HandshakeStatus handshakeStatus;
Status status;
- while(appData.hasRemaining() && !_sslStatus.getSslErrorFlag())
+ while(appData.hasRemaining() && !error.get())
{
int read = 0;
try
@@ -163,7 +160,6 @@ public class SSLSender implements Sender<ByteBuffer>
}
catch(SSLException e)
{
- // Should this set _sslError??
throw new SenderException("SSL, Error occurred while encrypting data",e);
}
@@ -211,7 +207,7 @@ public class SSLSender implements Sender<ByteBuffer>
case NEED_UNWRAP:
flush();
- synchronized(_sslStatus.getSslLock())
+ synchronized(engineState)
{
switch (engine.getHandshakeStatus())
{
@@ -219,7 +215,7 @@ public class SSLSender implements Sender<ByteBuffer>
long start = System.currentTimeMillis();
try
{
- _sslStatus.getSslLock().wait(timeout);
+ engineState.wait(timeout);
}
catch(InterruptedException e)
{
@@ -238,9 +234,9 @@ public class SSLSender implements Sender<ByteBuffer>
break;
case FINISHED:
- if (_hostname != null)
+ if (this.settings != null && this.settings.isVerifyHostname() )
{
- SSLUtil.verifyHostname(engine, _hostname);
+ SSLUtil.verifyHostname(engine, this.settings.getHost());
}
case NOT_HANDSHAKING:
@@ -253,7 +249,7 @@ public class SSLSender implements Sender<ByteBuffer>
}
}
- private void doTasks()
+ public void doTasks()
{
Runnable runnable;
while ((runnable = engine.getDelegatedTask()) != null) {
@@ -261,6 +257,16 @@ public class SSLSender implements Sender<ByteBuffer>
}
}
+ public Object getNotificationToken()
+ {
+ return engineState;
+ }
+
+ public void setErrorFlag()
+ {
+ error.set(true);
+ }
+
public void setIdleTimeout(int i)
{
delegate.setIdleTimeout(i);
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java b/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java
index 6bb038a581..fd73915b65 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/security/ssl/SSLUtil.java
@@ -125,6 +125,38 @@ public class SSLUtil
return id.toString();
}
+ public static SSLContext createSSLContext(ConnectionSettings settings) throws Exception
+ {
+ SSLContextFactory sslContextFactory;
+
+ if (settings.getCertAlias() == null)
+ {
+ sslContextFactory =
+ new SSLContextFactory(settings.getTrustStorePath(),
+ settings.getTrustStorePassword(),
+ settings.getTrustStoreCertType(),
+ settings.getKeyStorePath(),
+ settings.getKeyStorePassword(),
+ settings.getKeyStoreCertType());
+
+ } else
+ {
+ sslContextFactory =
+ new SSLContextFactory(settings.getTrustStorePath(),
+ settings.getTrustStorePassword(),
+ settings.getTrustStoreCertType(),
+ new QpidClientX509KeyManager(settings.getCertAlias(),
+ settings.getKeyStorePath(),
+ settings.getKeyStorePassword(),
+ settings.getKeyStoreCertType()));
+
+ log.debug("Using custom key manager");
+ }
+
+ return sslContextFactory.buildServerContext();
+
+ }
+
public static KeyStore getInitializedKeyStore(String storePath, String storePassword) throws GeneralSecurityException, IOException
{
KeyStore ks = KeyStore.getInstance("JKS");
@@ -144,10 +176,7 @@ public class SSLUtil
{
throw new IOException("Unable to load keystore resource: " + storePath);
}
-
- char[] storeCharPassword = storePassword == null ? null : storePassword.toCharArray();
-
- ks.load(in, storeCharPassword);
+ ks.load(in, storePassword.toCharArray());
}
finally
{
diff --git a/java/common/src/main/java/org/apache/qpid/url/URLHelper.java b/java/common/src/main/java/org/apache/qpid/url/URLHelper.java
index e261860bf3..6f21c327e7 100644
--- a/java/common/src/main/java/org/apache/qpid/url/URLHelper.java
+++ b/java/common/src/main/java/org/apache/qpid/url/URLHelper.java
@@ -31,6 +31,9 @@ public class URLHelper
public static void parseOptions(Map<String, String> optionMap, String options) throws URLSyntaxException
{
+ // options looks like this
+ // brokerlist='tcp://host:port?option='value',option='value';vm://:3/virtualpath?option='value'',failover='method?option='value',option='value''
+
if ((options == null) || (options.indexOf('=') == -1))
{
return;
diff --git a/java/common/src/main/java/org/apache/qpid/util/FileUtils.java b/java/common/src/main/java/org/apache/qpid/util/FileUtils.java
index ac8e3da3c2..516204fbd3 100644
--- a/java/common/src/main/java/org/apache/qpid/util/FileUtils.java
+++ b/java/common/src/main/java/org/apache/qpid/util/FileUtils.java
@@ -143,9 +143,8 @@ public class FileUtils
}
/**
- * Either opens the specified filename as an input stream or either the filesystem or classpath,
- * or uses the default resource loaded using the specified class loader, if opening the file fails
- * or no file name is specified.
+ * Either opens the specified filename as an input stream, or uses the default resource loaded using the
+ * specified class loader, if opening the file fails or no file name is specified.
*
* @param filename The name of the file to open.
* @param defaultResource The name of the default resource on the classpath if the file cannot be opened.
@@ -157,28 +156,28 @@ public class FileUtils
{
InputStream is = null;
+ // Flag to indicate whether the default resource should be used. By default this is true, so that the default
+ // is used when opening the file fails.
+ boolean useDefault = true;
+
// Try to open the file if one was specified.
if (filename != null)
{
- // try on filesystem
try
{
is = new BufferedInputStream(new FileInputStream(new File(filename)));
+
+ // Clear the default flag because the file was succesfully opened.
+ useDefault = false;
}
catch (FileNotFoundException e)
{
- is = null;
- }
-
- if (is == null)
- {
- // failed on filesystem, so try on classpath
- is = cl.getResourceAsStream(filename);
+ // Ignore this exception, the default will be used instead.
}
}
// Load the default resource if a file was not specified, or if opening the file failed.
- if (is == null)
+ if (useDefault)
{
is = cl.getResourceAsStream(defaultResource);
}
@@ -340,7 +339,7 @@ public class FileUtils
}
//else we have a source directory
- if (!dst.isDirectory() && !dst.mkdirs())
+ if (!dst.isDirectory() && !dst.mkdir())
{
throw new UnableToCopyException("Unable to create destination directory");
}
diff --git a/java/common/src/test/java/org/apache/mina/SocketIOTest/IOWriterClient.java b/java/common/src/test/java/org/apache/mina/SocketIOTest/IOWriterClient.java
new file mode 100644
index 0000000000..b93dc46741
--- /dev/null
+++ b/java/common/src/test/java/org/apache/mina/SocketIOTest/IOWriterClient.java
@@ -0,0 +1,396 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.mina.SocketIOTest;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.CloseFuture;
+import org.apache.mina.common.ConnectFuture;
+import org.apache.mina.common.IoConnector;
+import org.apache.mina.common.IoFilterChain;
+import org.apache.mina.common.IoHandlerAdapter;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.common.SimpleByteBufferAllocator;
+import org.apache.mina.filter.ReadThrottleFilterBuilder;
+import org.apache.mina.filter.WriteBufferLimitFilterBuilder;
+import org.apache.mina.transport.socket.nio.SocketSessionConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.concurrent.CountDownLatch;
+
+public class IOWriterClient implements Runnable
+{
+ private static final Logger _logger = LoggerFactory.getLogger(IOWriterClient.class);
+
+ public static int DEFAULT_TEST_SIZE = 2;
+
+ private IoSession _session;
+
+ private long _startTime;
+
+ private long[] _chunkTimes;
+
+ public int _chunkCount = 200000;
+
+ private int _chunkSize = 1024;
+
+ private CountDownLatch _notifier;
+
+ private int _maximumWriteQueueLength;
+
+ static public int _PORT = IOWriterServer._PORT;
+
+ public void run()
+ {
+ _logger.info("Starting to send " + _chunkCount + " buffers of " + _chunkSize + "B");
+ _startTime = System.currentTimeMillis();
+ _notifier = new CountDownLatch(1);
+
+ for (int i = 0; i < _chunkCount; i++)
+ {
+ ByteBuffer buf = ByteBuffer.allocate(_chunkSize, false);
+ byte check = (byte) (i % 128);
+ buf.put(check);
+ buf.fill((byte) 88, buf.remaining());
+ buf.flip();
+
+ _session.write(buf);
+ }
+
+ long _sentall = System.currentTimeMillis();
+ long _receivedall = _sentall;
+ try
+ {
+ _logger.info("All buffers sent; waiting for receipt from server");
+ _notifier.await();
+ _receivedall = System.currentTimeMillis();
+ }
+ catch (InterruptedException e)
+ {
+ //Ignore
+ }
+ _logger.info("Completed");
+ _logger.info("Total time waiting for server after last write: " + (_receivedall - _sentall));
+
+ long totalTime = System.currentTimeMillis() - _startTime;
+
+ _logger.info("Total time: " + totalTime);
+ _logger.info("MB per second: " + (int) ((1.0 * _chunkSize * _chunkCount) / totalTime));
+ long lastChunkTime = _startTime;
+ double average = 0;
+ for (int i = 0; i < _chunkTimes.length; i++)
+ {
+ if (i == 0)
+ {
+ average = _chunkTimes[i] - _startTime;
+ }
+ else
+ {
+ long delta = _chunkTimes[i] - lastChunkTime;
+ if (delta != 0)
+ {
+ average = (average + delta) / 2;
+ }
+ }
+ lastChunkTime = _chunkTimes[i];
+ }
+ _logger.info("Average chunk time: " + average + "ms");
+ _logger.info("Maximum WriteRequestQueue size: " + _maximumWriteQueueLength);
+
+ CloseFuture cf = _session.close();
+ _logger.info("Closing session");
+ cf.join();
+ }
+
+ private class WriterHandler extends IoHandlerAdapter
+ {
+ private int _chunksReceived = 0;
+
+ private int _partialBytesRead = 0;
+
+ private byte _partialCheckNumber;
+
+ private int _totalBytesReceived = 0;
+
+ private int _receivedCount = 0;
+ private int _sentCount = 0;
+ private static final String DEFAULT_READ_BUFFER = "262144";
+ private static final String DEFAULT_WRITE_BUFFER = "262144";
+
+ public void sessionCreated(IoSession session) throws Exception
+ {
+ IoFilterChain chain = session.getFilterChain();
+
+ ReadThrottleFilterBuilder readfilter = new ReadThrottleFilterBuilder();
+ readfilter.setMaximumConnectionBufferSize(Integer.parseInt(System.getProperty("qpid.read.buffer.limit", DEFAULT_READ_BUFFER)));
+ readfilter.attach(chain);
+
+ WriteBufferLimitFilterBuilder writefilter = new WriteBufferLimitFilterBuilder();
+
+ writefilter.setMaximumConnectionBufferSize(Integer.parseInt(System.getProperty("qpid.write.buffer.limit", DEFAULT_WRITE_BUFFER)));
+
+ writefilter.attach(chain);
+ }
+
+ public void messageSent(IoSession session, Object message) throws Exception
+ {
+ _maximumWriteQueueLength = Math.max(session.getScheduledWriteRequests(), _maximumWriteQueueLength);
+
+ if (_logger.isDebugEnabled())
+ {
+ ++_sentCount;
+ if (_sentCount % 1000 == 0)
+ {
+ _logger.debug("Sent count " + _sentCount + ":WQueue" + session.getScheduledWriteRequests());
+
+ }
+ }
+ }
+
+ public void messageReceived(IoSession session, Object message) throws Exception
+ {
+ if (_logger.isDebugEnabled())
+ {
+ ++_receivedCount;
+
+ if (_receivedCount % 1000 == 0)
+ {
+ _logger.debug("Receieved count " + _receivedCount);
+ }
+ }
+
+ ByteBuffer result = (ByteBuffer) message;
+ _totalBytesReceived += result.remaining();
+ int size = result.remaining();
+ long now = System.currentTimeMillis();
+ if (_partialBytesRead > 0)
+ {
+ int offset = _chunkSize - _partialBytesRead;
+ if (size >= offset)
+ {
+ _chunkTimes[_chunksReceived++] = now;
+ result.position(offset);
+ }
+ else
+ {
+ // have not read even one chunk, including the previous partial bytes
+ _partialBytesRead += size;
+ return;
+ }
+ }
+
+
+ int chunkCount = result.remaining() / _chunkSize;
+
+ for (int i = 0; i < chunkCount; i++)
+ {
+ _chunkTimes[_chunksReceived++] = now;
+ byte check = result.get();
+ _logger.debug("Check number " + check + " read");
+ if (check != (byte) ((_chunksReceived - 1) % 128))
+ {
+ _logger.error("Check number " + check + " read when expected " + (_chunksReceived % 128));
+ }
+ _logger.debug("Chunk times recorded");
+
+ try
+ {
+ result.skip(_chunkSize - 1);
+ }
+ catch (IllegalArgumentException e)
+ {
+ _logger.error("Position was: " + result.position());
+ _logger.error("Tried to skip to: " + (_chunkSize * i));
+ _logger.error("limit was; " + result.limit());
+ }
+ }
+ _logger.debug("Chunks received now " + _chunksReceived);
+ _logger.debug("Bytes received: " + _totalBytesReceived);
+ _partialBytesRead = result.remaining();
+
+ if (_partialBytesRead > 0)
+ {
+ _partialCheckNumber = result.get();
+ }
+
+
+ if (_chunksReceived >= _chunkCount)
+ {
+ _notifier.countDown();
+ }
+
+ }
+
+ public void exceptionCaught(IoSession session, Throwable cause) throws Exception
+ {
+ _logger.error("Error: " + cause, cause);
+ }
+ }
+
+ public void startWriter() throws IOException, InterruptedException
+ {
+
+ _maximumWriteQueueLength = 0;
+
+ IoConnector ioConnector = null;
+
+ if (Boolean.getBoolean("multinio"))
+ {
+ _logger.warn("Using MultiThread NIO");
+ ioConnector = new org.apache.mina.transport.socket.nio.MultiThreadSocketConnector();
+ }
+ else
+ {
+ _logger.warn("Using MINA NIO");
+ ioConnector = new org.apache.mina.transport.socket.nio.SocketConnector();
+ }
+
+ SocketSessionConfig scfg = (SocketSessionConfig) ioConnector.getDefaultConfig().getSessionConfig();
+ scfg.setTcpNoDelay(true);
+ scfg.setSendBufferSize(32768);
+ scfg.setReceiveBufferSize(32768);
+
+ ByteBuffer.setAllocator(new SimpleByteBufferAllocator());
+
+
+ final InetSocketAddress address = new InetSocketAddress("localhost", _PORT);
+ _logger.info("Attempting connection to " + address);
+
+ //Old mina style
+// ioConnector.setHandler(new WriterHandler());
+// ConnectFuture future = ioConnector.connect(address);
+ ConnectFuture future = ioConnector.connect(address, new WriterHandler());
+ // wait for connection to complete
+ future.join();
+ _logger.info("Connection completed");
+ // we call getSession which throws an IOException if there has been an error connecting
+ _session = future.getSession();
+
+ _chunkTimes = new long[_chunkCount];
+ Thread t = new Thread(this);
+ t.start();
+ t.join();
+ _logger.info("Test Complete");
+ }
+
+
+ public void test1k() throws IOException, InterruptedException
+ {
+ _logger.info("Starting 1k test");
+ _chunkSize = 1024;
+ startWriter();
+ }
+
+
+ public void test2k() throws IOException, InterruptedException
+ {
+ _logger.info("Starting 2k test");
+ _chunkSize = 2048;
+ startWriter();
+ }
+
+
+ public void test4k() throws IOException, InterruptedException
+ {
+ _logger.info("Starting 4k test");
+ _chunkSize = 4096;
+ startWriter();
+ }
+
+
+ public void test8k() throws IOException, InterruptedException
+ {
+ _logger.info("Starting 8k test");
+ _chunkSize = 8192;
+ startWriter();
+ }
+
+
+ public void test16k() throws IOException, InterruptedException
+ {
+ _logger.info("Starting 16k test");
+ _chunkSize = 16384;
+ startWriter();
+ }
+
+
+ public void test32k() throws IOException, InterruptedException
+ {
+ _logger.info("Starting 32k test");
+ _chunkSize = 32768;
+ startWriter();
+ }
+
+
+ public static int getIntArg(String[] args, int index, int defaultValue)
+ {
+ if (args.length > index)
+ {
+ try
+ {
+ return Integer.parseInt(args[index]);
+ }
+ catch (NumberFormatException e)
+ {
+ //Do nothing
+ }
+ }
+ return defaultValue;
+ }
+
+ public static void main(String[] args) throws IOException, InterruptedException
+ {
+ _PORT = getIntArg(args, 0, _PORT);
+
+ int test = getIntArg(args, 1, DEFAULT_TEST_SIZE);
+
+ IOWriterClient w = new IOWriterClient();
+ w._chunkCount = getIntArg(args, 2, w._chunkCount);
+ switch (test)
+ {
+ case 0:
+ w.test1k();
+ w.test2k();
+ w.test4k();
+ w.test8k();
+ w.test16k();
+ w.test32k();
+ break;
+ case 1:
+ w.test1k();
+ break;
+ case 2:
+ w.test2k();
+ break;
+ case 4:
+ w.test4k();
+ break;
+ case 8:
+ w.test8k();
+ break;
+ case 16:
+ w.test16k();
+ break;
+ case 32:
+ w.test32k();
+ break;
+ }
+ }
+}
diff --git a/java/common/src/test/java/org/apache/mina/SocketIOTest/IOWriterServer.java b/java/common/src/test/java/org/apache/mina/SocketIOTest/IOWriterServer.java
new file mode 100644
index 0000000000..423e98c67b
--- /dev/null
+++ b/java/common/src/test/java/org/apache/mina/SocketIOTest/IOWriterServer.java
@@ -0,0 +1,157 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.mina.SocketIOTest;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.common.IoAcceptor;
+import org.apache.mina.common.IoFilterChain;
+import org.apache.mina.common.IoHandlerAdapter;
+import org.apache.mina.common.IoSession;
+import org.apache.mina.common.SimpleByteBufferAllocator;
+import org.apache.mina.filter.ReadThrottleFilterBuilder;
+import org.apache.mina.filter.WriteBufferLimitFilterBuilder;
+import org.apache.mina.transport.socket.nio.SocketSessionConfig;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+
+/** Tests MINA socket performance. This acceptor simply reads data from the network and writes it back again. */
+public class IOWriterServer
+{
+ private static final Logger _logger = LoggerFactory.getLogger(IOWriterServer.class);
+
+ static public int _PORT = 9999;
+
+ private static final String DEFAULT_READ_BUFFER = "262144";
+ private static final String DEFAULT_WRITE_BUFFER = "262144";
+
+
+ private static class TestHandler extends IoHandlerAdapter
+ {
+ private int _sentCount = 0;
+
+ private int _bytesSent = 0;
+
+ private int _receivedCount = 0;
+
+ public void sessionCreated(IoSession ioSession) throws java.lang.Exception
+ {
+ IoFilterChain chain = ioSession.getFilterChain();
+
+ ReadThrottleFilterBuilder readfilter = new ReadThrottleFilterBuilder();
+ readfilter.setMaximumConnectionBufferSize(Integer.parseInt(System.getProperty("qpid.read.buffer.limit", DEFAULT_READ_BUFFER)));
+ readfilter.attach(chain);
+
+ WriteBufferLimitFilterBuilder writefilter = new WriteBufferLimitFilterBuilder();
+
+ writefilter.setMaximumConnectionBufferSize(Integer.parseInt(System.getProperty("qpid.write.buffer.limit", DEFAULT_WRITE_BUFFER)));
+
+ writefilter.attach(chain);
+
+ }
+
+ public void messageReceived(IoSession session, Object message) throws Exception
+ {
+ ((ByteBuffer) message).acquire();
+ session.write(message);
+
+ if (_logger.isDebugEnabled())
+ {
+ _bytesSent += ((ByteBuffer) message).remaining();
+
+ _sentCount++;
+
+ if (_sentCount % 1000 == 0)
+ {
+ _logger.debug("Bytes sent: " + _bytesSent);
+ }
+ }
+ }
+
+ public void messageSent(IoSession session, Object message) throws Exception
+ {
+ if (_logger.isDebugEnabled())
+ {
+ ++_receivedCount;
+
+ if (_receivedCount % 1000 == 0)
+ {
+ _logger.debug("Receieved count " + _receivedCount);
+ }
+ }
+ }
+
+ public void exceptionCaught(IoSession session, Throwable cause) throws Exception
+ {
+ _logger.error("Error: " + cause, cause);
+ }
+ }
+
+ public void startAcceptor() throws IOException
+ {
+ IoAcceptor acceptor;
+ if (Boolean.getBoolean("multinio"))
+ {
+ _logger.warn("Using MultiThread NIO");
+ acceptor = new org.apache.mina.transport.socket.nio.MultiThreadSocketAcceptor();
+ }
+ else
+ {
+ _logger.warn("Using MINA NIO");
+ acceptor = new org.apache.mina.transport.socket.nio.SocketAcceptor();
+ }
+
+
+ SocketSessionConfig sc = (SocketSessionConfig) acceptor.getDefaultConfig().getSessionConfig();
+ sc.setTcpNoDelay(true);
+ sc.setSendBufferSize(32768);
+ sc.setReceiveBufferSize(32768);
+
+ ByteBuffer.setAllocator(new SimpleByteBufferAllocator());
+
+ //The old mina style
+// acceptor.setLocalAddress(new InetSocketAddress(_PORT));
+// acceptor.setHandler(new TestHandler());
+// acceptor.bind();
+ acceptor.bind(new InetSocketAddress(_PORT), new TestHandler());
+
+ _logger.info("Bound on port " + _PORT + ":" + _logger.isDebugEnabled());
+ _logger.debug("debug on");
+ }
+
+ public static void main(String[] args) throws IOException
+ {
+
+ if (args.length > 0)
+ {
+ try
+ {
+ _PORT = Integer.parseInt(args[0]);
+ }
+ catch (NumberFormatException e)
+ {
+ //IGNORE so use default port 9999;
+ }
+ }
+
+ IOWriterServer a = new IOWriterServer();
+ a.startAcceptor();
+ }
+}
diff --git a/java/common/src/test/java/org/apache/qpid/AMQExceptionTest.java b/java/common/src/test/java/org/apache/qpid/AMQExceptionTest.java
index f65427e583..ef6cd41492 100644
--- a/java/common/src/test/java/org/apache/qpid/AMQExceptionTest.java
+++ b/java/common/src/test/java/org/apache/qpid/AMQExceptionTest.java
@@ -23,7 +23,6 @@ package org.apache.qpid;
import junit.framework.TestCase;
import org.apache.qpid.protocol.AMQConstant;
import org.apache.qpid.framing.AMQFrameDecodingException;
-import org.apache.qpid.framing.AMQShortString;
/**
* This test is to ensure that when an AMQException is rethrown that the specified exception is correctly wrapped up.
@@ -92,18 +91,6 @@ public class AMQExceptionTest extends TestCase
return amqe;
}
- public void testGetMessageAsString()
- {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < 25; i++)
- {
- sb.append("message [" + i + "]");
- }
- AMQException e = new AMQException(AMQConstant.INTERNAL_ERROR, sb.toString(), null);
- AMQShortString message = e.getMessageAsShortString();
- assertEquals(sb.substring(0, AMQShortString.MAX_LENGTH - 3) + "...", message.toString());
- }
-
/**
* Private class that extends AMQException but does not have a default exception.
*/
diff --git a/java/common/src/test/java/org/apache/qpid/codec/AMQDecoderTest.java b/java/common/src/test/java/org/apache/qpid/codec/AMQDecoderTest.java
index 272eb75800..62e25e7d79 100644
--- a/java/common/src/test/java/org/apache/qpid/codec/AMQDecoderTest.java
+++ b/java/common/src/test/java/org/apache/qpid/codec/AMQDecoderTest.java
@@ -21,9 +21,6 @@ package org.apache.qpid.codec;
*/
-import java.io.ByteArrayOutputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
@@ -49,16 +46,9 @@ public class AMQDecoderTest extends TestCase
}
- private ByteBuffer getHeartbeatBodyBuffer() throws IOException
+ public void testSingleFrameDecode() throws AMQProtocolVersionException, AMQFrameDecodingException
{
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- HeartbeatBody.FRAME.writePayload(new DataOutputStream(baos));
- return ByteBuffer.wrap(baos.toByteArray());
- }
-
- public void testSingleFrameDecode() throws AMQProtocolVersionException, AMQFrameDecodingException, IOException
- {
- ByteBuffer msg = getHeartbeatBodyBuffer();
+ ByteBuffer msg = HeartbeatBody.FRAME.toNioByteBuffer();
ArrayList<AMQDataBlock> frames = _decoder.decodeBuffer(msg);
if (frames.get(0) instanceof AMQFrame)
{
@@ -70,9 +60,9 @@ public class AMQDecoderTest extends TestCase
}
}
- public void testPartialFrameDecode() throws AMQProtocolVersionException, AMQFrameDecodingException, IOException
+ public void testPartialFrameDecode() throws AMQProtocolVersionException, AMQFrameDecodingException
{
- ByteBuffer msg = getHeartbeatBodyBuffer();
+ ByteBuffer msg = HeartbeatBody.FRAME.toNioByteBuffer();
ByteBuffer msgA = msg.slice();
int msgbPos = msg.remaining() / 2;
int msgaLimit = msg.remaining() - msgbPos;
@@ -93,10 +83,10 @@ public class AMQDecoderTest extends TestCase
}
}
- public void testMultipleFrameDecode() throws AMQProtocolVersionException, AMQFrameDecodingException, IOException
+ public void testMultipleFrameDecode() throws AMQProtocolVersionException, AMQFrameDecodingException
{
- ByteBuffer msgA = getHeartbeatBodyBuffer();
- ByteBuffer msgB = getHeartbeatBodyBuffer();
+ ByteBuffer msgA = HeartbeatBody.FRAME.toNioByteBuffer();
+ ByteBuffer msgB = HeartbeatBody.FRAME.toNioByteBuffer();
ByteBuffer msg = ByteBuffer.allocate(msgA.remaining() + msgB.remaining());
msg.put(msgA);
msg.put(msgB);
@@ -116,11 +106,11 @@ public class AMQDecoderTest extends TestCase
}
}
- public void testMultiplePartialFrameDecode() throws AMQProtocolVersionException, AMQFrameDecodingException, IOException
+ public void testMultiplePartialFrameDecode() throws AMQProtocolVersionException, AMQFrameDecodingException
{
- ByteBuffer msgA = getHeartbeatBodyBuffer();
- ByteBuffer msgB = getHeartbeatBodyBuffer();
- ByteBuffer msgC = getHeartbeatBodyBuffer();
+ ByteBuffer msgA = HeartbeatBody.FRAME.toNioByteBuffer();
+ ByteBuffer msgB = HeartbeatBody.FRAME.toNioByteBuffer();
+ ByteBuffer msgC = HeartbeatBody.FRAME.toNioByteBuffer();
ByteBuffer sliceA = ByteBuffer.allocate(msgA.remaining() + msgB.remaining() / 2);
sliceA.put(msgA);
diff --git a/java/common/src/test/java/org/apache/qpid/framing/AMQShortStringTest.java b/java/common/src/test/java/org/apache/qpid/framing/AMQShortStringTest.java
index 9a805d87b3..92e7ce0a80 100644
--- a/java/common/src/test/java/org/apache/qpid/framing/AMQShortStringTest.java
+++ b/java/common/src/test/java/org/apache/qpid/framing/AMQShortStringTest.java
@@ -20,10 +20,6 @@
package org.apache.qpid.framing;
-import java.io.UnsupportedEncodingException;
-import java.util.ArrayList;
-import java.util.List;
-
import junit.framework.TestCase;
public class AMQShortStringTest extends TestCase
{
@@ -109,215 +105,5 @@ public class AMQShortStringTest extends TestCase
assertFalse(new AMQShortString("A").equals(new AMQShortString("a")));
}
- /**
- * Test method for
- * {@link org.apache.qpid.framing.AMQShortString#AMQShortString(byte[])}.
- */
- public void testCreateAMQShortStringByteArray()
- {
- byte[] bytes = null;
- try
- {
- bytes = "test".getBytes("UTF-8");
- }
- catch (UnsupportedEncodingException e)
- {
- fail("UTF-8 encoding is not supported anymore by JVM:" + e.getMessage());
- }
- AMQShortString string = new AMQShortString(bytes);
- assertEquals("constructed amq short string length differs from expected", 4, string.length());
- assertTrue("constructed amq short string differs from expected", string.equals("test"));
- }
-
- /**
- * Test method for
- * {@link org.apache.qpid.framing.AMQShortString#AMQShortString(java.lang.String)}
- * <p>
- * Tests short string construction from string with length less than 255.
- */
- public void testCreateAMQShortStringString()
- {
- AMQShortString string = new AMQShortString("test");
- assertEquals("constructed amq short string length differs from expected", 4, string.length());
- assertTrue("constructed amq short string differs from expected", string.equals("test"));
- }
-
- /**
- * Test method for
- * {@link org.apache.qpid.framing.AMQShortString#AMQShortString(char[])}.
- * <p>
- * Tests short string construction from char array with length less than 255.
- */
- public void testCreateAMQShortStringCharArray()
- {
- char[] chars = "test".toCharArray();
- AMQShortString string = new AMQShortString(chars);
- assertEquals("constructed amq short string length differs from expected", 4, string.length());
- assertTrue("constructed amq short string differs from expected", string.equals("test"));
- }
-
- /**
- * Test method for
- * {@link org.apache.qpid.framing.AMQShortString#AMQShortString(java.lang.CharSequence)}
- * <p>
- * Tests short string construction from char sequence with length less than 255.
- */
- public void testCreateAMQShortStringCharSequence()
- {
- AMQShortString string = new AMQShortString((CharSequence) "test");
- assertEquals("constructed amq short string length differs from expected", 4, string.length());
- assertTrue("constructed amq short string differs from expected", string.equals("test"));
- }
-
- /**
- * Test method for
- * {@link org.apache.qpid.framing.AMQShortString#AMQShortString(byte[])}.
- * <p>
- * Tests an attempt to create an AMQP short string from byte array with length over 255.
- */
- public void testCreateAMQShortStringByteArrayOver255()
- {
- String test = buildString('a', 256);
- byte[] bytes = null;
- try
- {
- bytes = test.getBytes("UTF-8");
- }
- catch (UnsupportedEncodingException e)
- {
- fail("UTF-8 encoding is not supported anymore by JVM:" + e.getMessage());
- }
- try
- {
- new AMQShortString(bytes);
- fail("It should not be possible to create AMQShortString with length over 255");
- }
- catch (IllegalArgumentException e)
- {
- assertEquals("Exception message differs from expected",
- "Cannot create AMQShortString with number of octets over 255!", e.getMessage());
- }
- }
-
- /**
- * Test method for
- * {@link org.apache.qpid.framing.AMQShortString#AMQShortString(java.lang.String)}
- * <p>
- * Tests an attempt to create an AMQP short string from string with length over 255
- */
- public void testCreateAMQShortStringStringOver255()
- {
- String test = buildString('a', 256);
- try
- {
- new AMQShortString(test);
- fail("It should not be possible to create AMQShortString with length over 255");
- }
- catch (IllegalArgumentException e)
- {
- assertEquals("Exception message differs from expected",
- "Cannot create AMQShortString with number of octets over 255!", e.getMessage());
- }
- }
-
- /**
- * Test method for
- * {@link org.apache.qpid.framing.AMQShortString#AMQShortString(char[])}.
- * <p>
- * Tests an attempt to create an AMQP short string from char array with length over 255.
- */
- public void testCreateAMQShortStringCharArrayOver255()
- {
- String test = buildString('a', 256);
- char[] chars = test.toCharArray();
- try
- {
- new AMQShortString(chars);
- fail("It should not be possible to create AMQShortString with length over 255");
- }
- catch (IllegalArgumentException e)
- {
- assertEquals("Exception message differs from expected",
- "Cannot create AMQShortString with number of octets over 255!", e.getMessage());
- }
- }
-
- /**
- * Test method for
- * {@link org.apache.qpid.framing.AMQShortString#AMQShortString(java.lang.CharSequence)}
- * <p>
- * Tests an attempt to create an AMQP short string from char sequence with length over 255.
- */
- public void testCreateAMQShortStringCharSequenceOver255()
- {
- String test = buildString('a', 256);
- try
- {
- new AMQShortString((CharSequence) test);
- fail("It should not be possible to create AMQShortString with length over 255");
- }
- catch (IllegalArgumentException e)
- {
- assertEquals("Exception message differs from expected",
- "Cannot create AMQShortString with number of octets over 255!", e.getMessage());
- }
- }
-
- /**
- * Tests joining of short strings into a short string with length over 255.
- */
- public void testJoinOverflow()
- {
- List<AMQShortString> data = new ArrayList<AMQShortString>();
- for (int i = 0; i < 25; i++)
- {
- data.add(new AMQShortString("test data!"));
- }
- try
- {
- AMQShortString.join(data, new AMQShortString(" "));
- fail("It should not be possible to create AMQShortString with length over 255");
- }
- catch (IllegalArgumentException e)
- {
- assertEquals("Exception message differs from expected",
- "Cannot create AMQShortString with number of octets over 255!", e.getMessage());
- }
- }
-
- /**
- * Tests joining of short strings into a short string with length less than 255.
- */
- public void testJoin()
- {
- StringBuilder expected = new StringBuilder();
- List<AMQShortString> data = new ArrayList<AMQShortString>();
- data.add(new AMQShortString("test data 1"));
- expected.append("test data 1");
- data.add(new AMQShortString("test data 2"));
- expected.append(" test data 2");
- AMQShortString result = AMQShortString.join(data, new AMQShortString(" "));
- assertEquals("join result differs from expected", expected.toString(), result.asString());
- }
-
- /**
- * A helper method to generate a string with given length containing given
- * character
- *
- * @param ch
- * char to build string with
- * @param length
- * target string length
- * @return string
- */
- private String buildString(char ch, int length)
- {
- StringBuilder sb = new StringBuilder();
- for (int i = 0; i < length; i++)
- {
- sb.append(ch);
- }
- return sb.toString();
- }
}
diff --git a/java/common/src/test/java/org/apache/qpid/framing/BasicContentHeaderPropertiesTest.java b/java/common/src/test/java/org/apache/qpid/framing/BasicContentHeaderPropertiesTest.java
index 5e7783f492..4fd1f60d69 100644
--- a/java/common/src/test/java/org/apache/qpid/framing/BasicContentHeaderPropertiesTest.java
+++ b/java/common/src/test/java/org/apache/qpid/framing/BasicContentHeaderPropertiesTest.java
@@ -20,9 +20,9 @@
*/
package org.apache.qpid.framing;
-import junit.framework.TestCase;
+import org.apache.mina.common.ByteBuffer;
-import java.io.*;
+import junit.framework.TestCase;
public class BasicContentHeaderPropertiesTest extends TestCase
@@ -76,14 +76,15 @@ public class BasicContentHeaderPropertiesTest extends TestCase
assertEquals(99, _testProperties.getPropertyFlags());
}
- public void testWritePropertyListPayload() throws IOException
+ public void testWritePropertyListPayload()
{
- _testProperties.writePropertyListPayload(new DataOutputStream(new ByteArrayOutputStream(300)));
+ ByteBuffer buf = ByteBuffer.allocate(300);
+ _testProperties.writePropertyListPayload(buf);
}
public void testPopulatePropertiesFromBuffer() throws Exception
{
- DataInputStream buf = new DataInputStream(new ByteArrayInputStream(new byte[300]));
+ ByteBuffer buf = ByteBuffer.allocate(300);
_testProperties.populatePropertiesFromBuffer(buf, 99, 99);
}
diff --git a/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java b/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java
index bb4c9c3884..d4691ba097 100644
--- a/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java
+++ b/java/common/src/test/java/org/apache/qpid/framing/PropertyFieldTableTest.java
@@ -23,14 +23,14 @@ package org.apache.qpid.framing;
import junit.framework.Assert;
import junit.framework.TestCase;
+import org.apache.mina.common.ByteBuffer;
+
import org.apache.qpid.AMQInvalidArgumentException;
import org.apache.qpid.AMQPInvalidClassException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.*;
-
public class PropertyFieldTableTest extends TestCase
{
private static final Logger _logger = LoggerFactory.getLogger(PropertyFieldTableTest.class);
@@ -441,7 +441,7 @@ public class PropertyFieldTableTest extends TestCase
}
/** Check that a nested field table parameter correctly encodes and decodes to a byte buffer. */
- public void testNestedFieldTable() throws IOException
+ public void testNestedFieldTable()
{
byte[] testBytes = new byte[] { 0, 1, 2, 3, 4, 5 };
@@ -465,16 +465,14 @@ public class PropertyFieldTableTest extends TestCase
outerTable.setFieldTable("innerTable", innerTable);
// Write the outer table into the buffer.
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
-
- outerTable.writeToBuffer(new DataOutputStream(baos));
-
- byte[] data = baos.toByteArray();
+ final ByteBuffer buffer = ByteBuffer.allocate((int) outerTable.getEncodedSize() + 4);
+ outerTable.writeToBuffer(buffer);
+ buffer.flip();
// Extract the table back from the buffer again.
try
{
- FieldTable extractedOuterTable = EncodingUtils.readFieldTable(new DataInputStream(new ByteArrayInputStream(data)));
+ FieldTable extractedOuterTable = EncodingUtils.readFieldTable(buffer);
FieldTable extractedTable = extractedOuterTable.getFieldTable("innerTable");
@@ -569,7 +567,7 @@ public class PropertyFieldTableTest extends TestCase
Assert.assertEquals("Hello", table.getObject("object-string"));
}
- public void testwriteBuffer() throws IOException
+ public void testwriteBuffer()
{
byte[] bytes = { 99, 98, 97, 96, 95 };
@@ -587,17 +585,15 @@ public class PropertyFieldTableTest extends TestCase
table.setString("string", "hello");
table.setString("null-string", null);
+ final ByteBuffer buffer = ByteBuffer.allocate((int) table.getEncodedSize() + 4); // FIXME XXX: Is cast a problem?
- ByteArrayOutputStream baos = new ByteArrayOutputStream((int) table.getEncodedSize() + 4);
- table.writeToBuffer(new DataOutputStream(baos));
-
- ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
- DataInputStream dis = new DataInputStream(bais);
+ table.writeToBuffer(buffer);
+ buffer.flip();
- long length = dis.readInt() & 0xFFFFFFFFL;
+ long length = buffer.getUnsignedInt();
- FieldTable table2 = new FieldTable(dis, length);
+ FieldTable table2 = new FieldTable(buffer, length);
Assert.assertEquals((Boolean) true, table2.getBoolean("bool"));
Assert.assertEquals((Byte) Byte.MAX_VALUE, table2.getByte("byte"));
diff --git a/java/common/src/test/java/org/apache/qpid/session/TestSession.java b/java/common/src/test/java/org/apache/qpid/session/TestSession.java
new file mode 100644
index 0000000000..aafc91b03b
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/session/TestSession.java
@@ -0,0 +1,277 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.session;
+
+import org.apache.mina.common.*;
+
+import java.net.SocketAddress;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class TestSession implements IoSession
+{
+ private final ConcurrentMap attributes = new ConcurrentHashMap();
+
+ public TestSession()
+ {
+ }
+
+ public IoService getService()
+ {
+ return null; //TODO
+ }
+
+ public IoServiceConfig getServiceConfig()
+ {
+ return null; //TODO
+ }
+
+ public IoHandler getHandler()
+ {
+ return null; //TODO
+ }
+
+ public IoSessionConfig getConfig()
+ {
+ return null; //TODO
+ }
+
+ public IoFilterChain getFilterChain()
+ {
+ return null; //TODO
+ }
+
+ public WriteFuture write(Object message)
+ {
+ return null; //TODO
+ }
+
+ public CloseFuture close()
+ {
+ return null; //TODO
+ }
+
+ public Object getAttachment()
+ {
+ return getAttribute("");
+ }
+
+ public Object setAttachment(Object attachment)
+ {
+ return setAttribute("",attachment);
+ }
+
+ public Object getAttribute(String key)
+ {
+ return attributes.get(key);
+ }
+
+ public Object setAttribute(String key, Object value)
+ {
+ return attributes.put(key,value);
+ }
+
+ public Object setAttribute(String key)
+ {
+ return attributes.put(key, Boolean.TRUE);
+ }
+
+ public Object removeAttribute(String key)
+ {
+ return attributes.remove(key);
+ }
+
+ public boolean containsAttribute(String key)
+ {
+ return attributes.containsKey(key);
+ }
+
+ public Set getAttributeKeys()
+ {
+ return attributes.keySet();
+ }
+
+ public TransportType getTransportType()
+ {
+ return null; //TODO
+ }
+
+ public boolean isConnected()
+ {
+ return false; //TODO
+ }
+
+ public boolean isClosing()
+ {
+ return false; //TODO
+ }
+
+ public CloseFuture getCloseFuture()
+ {
+ return null; //TODO
+ }
+
+ public SocketAddress getRemoteAddress()
+ {
+ return null; //TODO
+ }
+
+ public SocketAddress getLocalAddress()
+ {
+ return null; //TODO
+ }
+
+ public SocketAddress getServiceAddress()
+ {
+ return null; //TODO
+ }
+
+ public int getIdleTime(IdleStatus status)
+ {
+ return 0; //TODO
+ }
+
+ public long getIdleTimeInMillis(IdleStatus status)
+ {
+ return 0; //TODO
+ }
+
+ public void setIdleTime(IdleStatus status, int idleTime)
+ {
+ //TODO
+ }
+
+ public int getWriteTimeout()
+ {
+ return 0; //TODO
+ }
+
+ public long getWriteTimeoutInMillis()
+ {
+ return 0; //TODO
+ }
+
+ public void setWriteTimeout(int writeTimeout)
+ {
+ //TODO
+ }
+
+ public TrafficMask getTrafficMask()
+ {
+ return null; //TODO
+ }
+
+ public void setTrafficMask(TrafficMask trafficMask)
+ {
+ //TODO
+ }
+
+ public void suspendRead()
+ {
+ //TODO
+ }
+
+ public void suspendWrite()
+ {
+ //TODO
+ }
+
+ public void resumeRead()
+ {
+ //TODO
+ }
+
+ public void resumeWrite()
+ {
+ //TODO
+ }
+
+ public long getReadBytes()
+ {
+ return 0; //TODO
+ }
+
+ public long getWrittenBytes()
+ {
+ return 0; //TODO
+ }
+
+ public long getReadMessages()
+ {
+ return 0;
+ }
+
+ public long getWrittenMessages()
+ {
+ return 0;
+ }
+
+ public long getWrittenWriteRequests()
+ {
+ return 0; //TODO
+ }
+
+ public int getScheduledWriteRequests()
+ {
+ return 0; //TODO
+ }
+
+ public int getScheduledWriteBytes()
+ {
+ return 0; //TODO
+ }
+
+ public long getCreationTime()
+ {
+ return 0; //TODO
+ }
+
+ public long getLastIoTime()
+ {
+ return 0; //TODO
+ }
+
+ public long getLastReadTime()
+ {
+ return 0; //TODO
+ }
+
+ public long getLastWriteTime()
+ {
+ return 0; //TODO
+ }
+
+ public boolean isIdle(IdleStatus status)
+ {
+ return false; //TODO
+ }
+
+ public int getIdleCount(IdleStatus status)
+ {
+ return 0; //TODO
+ }
+
+ public long getLastIdleTime(IdleStatus status)
+ {
+ return 0; //TODO
+ }
+}
diff --git a/java/common/src/test/java/org/apache/qpid/ssl/SSLContextFactoryTest.java b/java/common/src/test/java/org/apache/qpid/ssl/SSLContextFactoryTest.java
deleted file mode 100644
index 288946e064..0000000000
--- a/java/common/src/test/java/org/apache/qpid/ssl/SSLContextFactoryTest.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/* Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.ssl;
-
-import java.io.IOException;
-
-import javax.net.ssl.SSLContext;
-
-import org.apache.qpid.test.utils.QpidTestCase;
-
-public class SSLContextFactoryTest extends QpidTestCase
-{
- private static final String BROKER_KEYSTORE_PATH = TEST_RESOURCES_DIR + "/ssl/java_broker_keystore.jks";
- private static final String CLIENT_KEYSTORE_PATH = TEST_RESOURCES_DIR + "/ssl/java_client_keystore.jks";
- private static final String CLIENT_TRUSTSTORE_PATH = TEST_RESOURCES_DIR + "/ssl/java_client_truststore.jks";
- private static final String STORE_PASSWORD = "password";
- private static final String CERT_TYPE = "SunX509";
- private static final String CERT_ALIAS_APP1 = "app1";
-
- public void testBuildServerContext() throws Exception
- {
- SSLContext context = SSLContextFactory.buildServerContext(BROKER_KEYSTORE_PATH, STORE_PASSWORD, CERT_TYPE);
- assertNotNull("SSLContext should not be null", context);
- }
-
- public void testBuildServerContextWithIncorrectPassword() throws Exception
- {
- try
- {
- SSLContextFactory.buildServerContext(BROKER_KEYSTORE_PATH, "sajdklsad", CERT_TYPE);
- fail("Exception was not thrown due to incorrect password");
- }
- catch (IOException e)
- {
- //expected
- }
- }
-
- public void testTrustStoreDoesNotExist() throws Exception
- {
- try
- {
- SSLContextFactory.buildClientContext("/path/to/nothing", STORE_PASSWORD, CERT_TYPE, CLIENT_KEYSTORE_PATH, STORE_PASSWORD, CERT_TYPE, null);
- fail("Exception was not thrown due to incorrect path");
- }
- catch (IOException e)
- {
- //expected
- }
- }
-
- public void testBuildClientContextForSSLEncryptionOnly() throws Exception
- {
- SSLContext context = SSLContextFactory.buildClientContext(CLIENT_TRUSTSTORE_PATH, STORE_PASSWORD, CERT_TYPE, null, null, null, null);
- assertNotNull("SSLContext should not be null", context);
- }
-
- public void testBuildClientContextWithForClientAuth() throws Exception
- {
- SSLContext context = SSLContextFactory.buildClientContext(CLIENT_TRUSTSTORE_PATH, STORE_PASSWORD, CERT_TYPE, CLIENT_KEYSTORE_PATH, STORE_PASSWORD, CERT_TYPE, null);
- assertNotNull("SSLContext should not be null", context);
- }
-
- public void testBuildClientContextWithForClientAuthWithCertAlias() throws Exception
- {
- SSLContext context = SSLContextFactory.buildClientContext(CLIENT_TRUSTSTORE_PATH, STORE_PASSWORD, CERT_TYPE, CLIENT_KEYSTORE_PATH, STORE_PASSWORD, CERT_TYPE, CERT_ALIAS_APP1);
- assertNotNull("SSLContext should not be null", context);
- }
-}
diff --git a/java/common/src/test/java/org/apache/qpid/test/utils/QpidTestCase.java b/java/common/src/test/java/org/apache/qpid/test/utils/QpidTestCase.java
index e69f95f916..8b470d555e 100644
--- a/java/common/src/test/java/org/apache/qpid/test/utils/QpidTestCase.java
+++ b/java/common/src/test/java/org/apache/qpid/test/utils/QpidTestCase.java
@@ -24,28 +24,17 @@ import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
-import java.net.DatagramSocket;
-import java.net.ServerSocket;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.List;
import junit.framework.TestCase;
import junit.framework.TestResult;
-import org.apache.log4j.Level;
import org.apache.log4j.Logger;
-
public class QpidTestCase extends TestCase
{
- public static final String QPID_HOME = System.getProperty("QPID_HOME");
- public static final String TEST_RESOURCES_DIR = QPID_HOME + "/../test-profiles/test_resources/";
-
- private static final Logger _logger = Logger.getLogger(QpidTestCase.class);
-
- private final Map<Logger, Level> _loggerLevelSetForTest = new HashMap<Logger, Level>();
- private final Map<String, String> _propertiesSetForTest = new HashMap<String, String>();
-
- private String _testName;
+ protected static final Logger _logger = Logger.getLogger(QpidTestCase.class);
/**
* Some tests are excluded when the property test.excludes is set to true.
@@ -65,7 +54,7 @@ public class QpidTestCase extends TestCase
String exclusionListString = System.getProperties().getProperty("test.excludelist", "");
List<String> exclusionList = new ArrayList<String>();
- for (String uri : exclusionListURIs.split(";\\s*"))
+ for (String uri : exclusionListURIs.split("\\s+"))
{
File file = new File(uri);
if (file.exists())
@@ -87,10 +76,6 @@ public class QpidTestCase extends TestCase
_logger.warn("Exception when reading exclusion list", e);
}
}
- else
- {
- _logger.info("Specified exclude file does not exist: " + uri);
- }
}
if (!exclusionListString.equals(""))
@@ -142,187 +127,4 @@ public class QpidTestCase extends TestCase
return storeClass != null ? storeClass : MEMORY_STORE_CLASS_NAME ;
}
-
-
- public static final int MIN_PORT_NUMBER = 1;
- public static final int MAX_PORT_NUMBER = 49151;
-
-
- /**
- * Gets the next available port starting at a port.
- *
- * @param fromPort the port to scan for availability
- * @throws NoSuchElementException if there are no ports available
- */
- protected int getNextAvailable(int fromPort)
- {
- if ((fromPort < MIN_PORT_NUMBER) || (fromPort > MAX_PORT_NUMBER))
- {
- throw new IllegalArgumentException("Invalid start port: " + fromPort);
- }
-
- for (int i = fromPort; i <= MAX_PORT_NUMBER; i++)
- {
- if (available(i)) {
- return i;
- }
- }
-
- throw new NoSuchElementException("Could not find an available port above " + fromPort);
- }
-
- /**
- * Checks to see if a specific port is available.
- *
- * @param port the port to check for availability
- */
- private boolean available(int port)
- {
- if ((port < MIN_PORT_NUMBER) || (port > MAX_PORT_NUMBER))
- {
- throw new IllegalArgumentException("Invalid start port: " + port);
- }
-
- ServerSocket ss = null;
- DatagramSocket ds = null;
- try
- {
- ss = new ServerSocket(port);
- ss.setReuseAddress(true);
- ds = new DatagramSocket(port);
- ds.setReuseAddress(true);
- return true;
- }
- catch (IOException e)
- {
- }
- finally
- {
- if (ds != null)
- {
- ds.close();
- }
-
- if (ss != null)
- {
- try
- {
- ss.close();
- }
- catch (IOException e)
- {
- /* should not be thrown */
- }
- }
- }
-
- return false;
- }
-
- public int findFreePort()
- {
- return getNextAvailable(10000);
- }
-
- /**
- * Set a System property for duration of this test only. The tearDown will
- * guarantee to reset the property to its previous value after the test
- * completes.
- *
- * @param property The property to set
- * @param value the value to set it to, if null, the property will be cleared
- */
- protected void setTestSystemProperty(final String property, final String value)
- {
- if (!_propertiesSetForTest.containsKey(property))
- {
- // Record the current value so we can revert it later.
- _propertiesSetForTest.put(property, System.getProperty(property));
- }
-
- if (value == null)
- {
- System.clearProperty(property);
- }
- else
- {
- System.setProperty(property, value);
- }
- }
-
- /**
- * Restore the System property values that were set by this test run.
- */
- protected void revertTestSystemProperties()
- {
- if(!_propertiesSetForTest.isEmpty())
- {
- _logger.debug("reverting " + _propertiesSetForTest.size() + " test properties");
- for (String key : _propertiesSetForTest.keySet())
- {
- String value = _propertiesSetForTest.get(key);
- if (value != null)
- {
- System.setProperty(key, value);
- }
- else
- {
- System.clearProperty(key);
- }
- }
-
- _propertiesSetForTest.clear();
- }
- }
-
- /**
- * Adjust the VMs Log4j Settings just for this test run
- *
- * @param logger the logger to change
- * @param level the level to set
- */
- protected void setLoggerLevel(Logger logger, Level level)
- {
- assertNotNull("Cannot set level of null logger", logger);
- assertNotNull("Cannot set Logger("+logger.getName()+") to null level.",level);
-
- if (!_loggerLevelSetForTest.containsKey(logger))
- {
- // Record the current value so we can revert it later.
- _loggerLevelSetForTest.put(logger, logger.getLevel());
- }
-
- logger.setLevel(level);
- }
-
- /**
- * Restore the logging levels defined by this test.
- */
- protected void revertLoggingLevels()
- {
- for (Logger logger : _loggerLevelSetForTest.keySet())
- {
- logger.setLevel(_loggerLevelSetForTest.get(logger));
- }
-
- _loggerLevelSetForTest.clear();
- }
-
- protected void tearDown() throws java.lang.Exception
- {
- _logger.info("========== tearDown " + _testName + " ==========");
- revertTestSystemProperties();
- revertLoggingLevels();
- }
-
- protected void setUp() throws Exception
- {
- _testName = getClass().getSimpleName() + "." + getName();
- _logger.info("========== start " + _testName + " ==========");
- }
-
- protected String getTestName()
- {
- return _testName;
- }
}
diff --git a/java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java b/java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java
index 49f6a08007..375a326654 100644
--- a/java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java
+++ b/java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java
@@ -20,27 +20,32 @@
*/
package org.apache.qpid.transport;
-import static org.apache.qpid.transport.Option.EXPECTED;
-import static org.apache.qpid.transport.Option.NONE;
-import static org.apache.qpid.transport.Option.SYNC;
+import org.apache.mina.util.AvailablePortFinder;
+
+import org.apache.qpid.test.utils.QpidTestCase;
+import org.apache.qpid.transport.network.ConnectionBinding;
+import org.apache.qpid.transport.network.io.IoAcceptor;
+import org.apache.qpid.transport.util.Logger;
+import org.apache.qpid.transport.util.Waiter;
-import java.io.IOException;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
+import java.util.Collections;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.io.IOException;
-import org.apache.qpid.test.utils.QpidTestCase;
-import org.apache.qpid.transport.network.ConnectionBinding;
-import org.apache.qpid.transport.network.io.IoAcceptor;
-import org.apache.qpid.transport.util.Waiter;
+import static org.apache.qpid.transport.Option.*;
/**
* ConnectionTest
*/
+
public class ConnectionTest extends QpidTestCase implements SessionListener
{
+
+ private static final Logger log = Logger.get(ConnectionTest.class);
+
private int port;
private volatile boolean queue = false;
private List<MessageTransfer> messages = new ArrayList<MessageTransfer>();
@@ -53,7 +58,7 @@ public class ConnectionTest extends QpidTestCase implements SessionListener
{
super.setUp();
- port = findFreePort();
+ port = AvailablePortFinder.getNextAvailable(12000);
}
protected void tearDown() throws Exception
@@ -153,8 +158,7 @@ public class ConnectionTest extends QpidTestCase implements SessionListener
private Connection connect(final CountDownLatch closed)
{
- final Connection conn = new Connection();
- conn.setConnectionDelegate(new ClientDelegate(new ConnectionSettings()));
+ Connection conn = new Connection();
conn.addConnectionListener(new ConnectionListener()
{
public void opened(Connection conn) {}
@@ -178,9 +182,9 @@ public class ConnectionTest extends QpidTestCase implements SessionListener
{
// Force os.name to be windows to exercise code in IoReceiver
// that looks for the value of os.name
- setTestSystemProperty("os.name","windows");
+ System.setProperty("os.name","windows");
- // Start server as 0-9 to force a ProtocolVersionException
+ // Start server as 0-9 to froce a ProtocolVersionException
startServer(new ProtocolHeader(1, 0, 9));
CountDownLatch closed = new CountDownLatch(1);
@@ -215,7 +219,7 @@ public class ConnectionTest extends QpidTestCase implements SessionListener
conn.send(protocolHeader);
List<Object> utf8 = new ArrayList<Object>();
utf8.add("utf8");
- conn.connectionStart(null, Collections.emptyList(), utf8);
+ conn.connectionStart(null, Collections.EMPTY_LIST, utf8);
}
@Override
@@ -266,7 +270,40 @@ public class ConnectionTest extends QpidTestCase implements SessionListener
}
}
+ class FailoverConnectionListener implements ConnectionListener
+ {
+ public void opened(Connection conn) {}
+
+ public void exception(Connection conn, ConnectionException e)
+ {
+ throw e;
+ }
+
+ public void closed(Connection conn)
+ {
+ queue = true;
+ conn.connect("localhost", port, null, "guest", "guest");
+ conn.resume();
+ }
+ }
+
+ class TestSessionListener implements SessionListener
+ {
+ public void opened(Session s) {}
+ public void resumed(Session s) {}
+ public void exception(Session s, SessionException e) {}
+ public void message(Session s, MessageTransfer xfr)
+ {
+ synchronized (incoming)
+ {
+ incoming.add(xfr);
+ incoming.notifyAll();
+ }
+ s.processed(xfr);
+ }
+ public void closed(Session s) {}
+ }
public void testResumeNonemptyReplayBuffer() throws Exception
{
@@ -274,7 +311,6 @@ public class ConnectionTest extends QpidTestCase implements SessionListener
Connection conn = new Connection();
conn.addConnectionListener(new FailoverConnectionListener());
- conn.setConnectionDelegate(new ClientDelegate(new ConnectionSettings()));
conn.connect("localhost", port, null, "guest", "guest");
Session ssn = conn.createSession(1);
ssn.setSessionListener(new TestSessionListener());
@@ -329,7 +365,6 @@ public class ConnectionTest extends QpidTestCase implements SessionListener
startServer();
Connection conn = new Connection();
- conn.setConnectionDelegate(new ClientDelegate(new ConnectionSettings()));
conn.addConnectionListener(new FailoverConnectionListener());
conn.connect("localhost", port, null, "guest", "guest");
Session ssn = conn.createSession(1);
@@ -352,7 +387,6 @@ public class ConnectionTest extends QpidTestCase implements SessionListener
startServer();
Connection conn = new Connection();
- conn.setConnectionDelegate(new ClientDelegate(new ConnectionSettings()));
conn.connect("localhost", port, null, "guest", "guest");
Session ssn = conn.createSession();
ssn.sessionFlush(EXPECTED);
@@ -366,7 +400,6 @@ public class ConnectionTest extends QpidTestCase implements SessionListener
{
startServer();
Connection conn = new Connection();
- conn.setConnectionDelegate(new ClientDelegate(new ConnectionSettings()));
conn.connect("localhost", port, null, "guest", "guest");
conn.connectionHeartbeat();
conn.close();
@@ -377,7 +410,6 @@ public class ConnectionTest extends QpidTestCase implements SessionListener
startServer();
Connection conn = new Connection();
- conn.setConnectionDelegate(new ClientDelegate(new ConnectionSettings()));
conn.connect("localhost", port, null, "guest", "guest");
Session ssn = conn.createSession();
send(ssn, "EXCP 0");
@@ -397,7 +429,6 @@ public class ConnectionTest extends QpidTestCase implements SessionListener
startServer();
Connection conn = new Connection();
- conn.setConnectionDelegate(new ClientDelegate(new ConnectionSettings()));
conn.connect("localhost", port, null, "guest", "guest");
Session ssn = conn.createSession();
send(ssn, "EXCP 0", true);
@@ -412,38 +443,4 @@ public class ConnectionTest extends QpidTestCase implements SessionListener
}
}
- class FailoverConnectionListener implements ConnectionListener
- {
- public void opened(Connection conn) {}
-
- public void exception(Connection conn, ConnectionException e)
- {
- throw e;
- }
-
- public void closed(Connection conn)
- {
- queue = true;
- conn.connect("localhost", port, null, "guest", "guest");
- conn.resume();
- }
- }
-
- class TestSessionListener implements SessionListener
- {
- public void opened(Session s) {}
- public void resumed(Session s) {}
- public void exception(Session s, SessionException e) {}
- public void message(Session s, MessageTransfer xfr)
- {
- synchronized (incoming)
- {
- incoming.add(xfr);
- incoming.notifyAll();
- }
-
- s.processed(xfr);
- }
- public void closed(Session s) {}
- }
}
diff --git a/java/common/src/test/java/org/apache/qpid/transport/SessionTimeoutTest.java b/java/common/src/test/java/org/apache/qpid/transport/SessionTimeoutTest.java
deleted file mode 100644
index 5f1c1254a2..0000000000
--- a/java/common/src/test/java/org/apache/qpid/transport/SessionTimeoutTest.java
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-package org.apache.qpid.transport;
-
-import org.apache.qpid.configuration.ClientProperties;
-import org.apache.qpid.test.utils.QpidTestCase;
-
-
-public class SessionTimeoutTest extends QpidTestCase
-{
- public void testSessionTimeout()
- {
- try
- {
- long timeout = 1;
- setTestSystemProperty("qpid.sync_op_timeout", Long.toString(timeout));
- assertSessionTimeout(timeout);
- }
- finally
- {
- revertTestSystemProperties();
- }
- }
-
- public void testSessionTimeoutSetWith_amqj_default_syncwrite_timeout()
- {
- try
- {
- long timeout = 1;
- setTestSystemProperty("amqj.default_syncwrite_timeout", Long.toString(timeout));
- setTestSystemProperty("qpid.sync_op_timeout", null);
- assertSessionTimeout(timeout);
- }
- finally
- {
- revertTestSystemProperties();
- }
- }
-
- private void assertSessionTimeout(long timeout)
- {
- Session session = new TestSession(null, null, 0);
- long startTime = System.currentTimeMillis();
- try
- {
- session.awaitOpen();
- fail("SessionTimeoutException is expected!");
- }
- catch (SessionException e)
- {
- long elapsedTime = System.currentTimeMillis() - startTime;
- assertTrue("Expected timeout should happened in " + timeout + " ms but timeout occured in "
- + elapsedTime + " ms!", elapsedTime >= timeout && elapsedTime < ClientProperties.DEFAULT_SYNC_OPERATION_TIMEOUT);
- }
- }
-
- class TestSession extends Session
- {
- public TestSession(Connection connection, Binary name, long expiry)
- {
- super(connection, name, expiry);
- }
- }
-
-}
diff --git a/java/common/src/test/java/org/apache/qpid/transport/TestNetworkConnection.java b/java/common/src/test/java/org/apache/qpid/transport/TestNetworkDriver.java
index 8533c64fab..957a7190ee 100644
--- a/java/common/src/test/java/org/apache/qpid/transport/TestNetworkConnection.java
+++ b/java/common/src/test/java/org/apache/qpid/transport/TestNetworkDriver.java
@@ -25,36 +25,34 @@ import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
import org.apache.qpid.protocol.ProtocolEngine;
import org.apache.qpid.protocol.ProtocolEngineFactory;
import org.apache.qpid.ssl.SSLContextFactory;
-import org.apache.qpid.transport.network.NetworkConnection;
/**
* Test implementation of IoSession, which is required for some tests. Methods not being used are not implemented,
* so if this class is being used and some methods are to be used, then please update those.
*/
-public class TestNetworkConnection implements NetworkConnection
+public class TestNetworkDriver implements NetworkDriver
{
+ private final ConcurrentMap attributes = new ConcurrentHashMap();
private String _remoteHost = "127.0.0.1";
private String _localHost = "127.0.0.1";
private int _port = 1;
private SocketAddress _localAddress = null;
private SocketAddress _remoteAddress = null;
- private final MockSender _sender;
- public TestNetworkConnection()
+ public TestNetworkDriver()
{
- _sender = new MockSender();
}
-
-
public void bind(int port, InetAddress[] addresses, ProtocolEngineFactory protocolFactory,
- NetworkTransportConfiguration config, SSLContextFactory sslFactory) throws BindException
+ NetworkDriverConfiguration config, SSLContextFactory sslFactory) throws BindException
{
-
+
}
public SocketAddress getLocalAddress()
@@ -67,40 +65,40 @@ public class TestNetworkConnection implements NetworkConnection
return (_remoteAddress != null) ? _remoteAddress : new InetSocketAddress(_remoteHost, _port);
}
- public void open(int port, InetAddress destination, ProtocolEngine engine, NetworkTransportConfiguration config,
+ public void open(int port, InetAddress destination, ProtocolEngine engine, NetworkDriverConfiguration config,
SSLContextFactory sslFactory) throws OpenException
{
-
+
}
public void setMaxReadIdle(int idleTime)
{
-
+
}
public void setMaxWriteIdle(int idleTime)
{
-
+
}
public void close()
{
-
+
}
public void flush()
{
-
+
}
public void send(ByteBuffer msg)
{
-
+
}
public void setIdleTimeout(int i)
{
-
+
}
public void setPort(int port)
@@ -132,13 +130,4 @@ public class TestNetworkConnection implements NetworkConnection
{
_remoteAddress = address;
}
-
- public Sender<ByteBuffer> getSender()
- {
- return _sender;
- }
-
- public void start()
- {
- }
}
diff --git a/java/common/src/test/java/org/apache/qpid/transport/network/TransportTest.java b/java/common/src/test/java/org/apache/qpid/transport/network/TransportTest.java
deleted file mode 100644
index 7039b904e3..0000000000
--- a/java/common/src/test/java/org/apache/qpid/transport/network/TransportTest.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
- */
-package org.apache.qpid.transport.network;
-
-
-import java.nio.ByteBuffer;
-
-import javax.net.ssl.SSLContext;
-
-import org.apache.qpid.framing.ProtocolVersion;
-import org.apache.qpid.protocol.ProtocolEngineFactory;
-import org.apache.qpid.test.utils.QpidTestCase;
-import org.apache.qpid.transport.ConnectionSettings;
-import org.apache.qpid.transport.NetworkTransportConfiguration;
-import org.apache.qpid.transport.Receiver;
-import org.apache.qpid.transport.TransportException;
-import org.apache.qpid.transport.network.io.IoNetworkTransport;
-
-public class TransportTest extends QpidTestCase
-{
-
-
-
- public void testDefaultGetOutgoingTransportForv0_8() throws Exception
- {
- final OutgoingNetworkTransport networkTransport = Transport.getOutgoingTransportInstance(ProtocolVersion.v8_0);
- assertNotNull(networkTransport);
- assertTrue(networkTransport instanceof IoNetworkTransport);
- }
-
- public void testGloballyOverriddenOutgoingTransportForv0_8() throws Exception
- {
- setTestSystemProperty(Transport.QPID_TRANSPORT_PROPNAME, TestOutgoingNetworkTransport.class.getName());
-
- final OutgoingNetworkTransport networkTransport = Transport.getOutgoingTransportInstance(ProtocolVersion.v8_0);
- assertNotNull(networkTransport);
- assertTrue(networkTransport instanceof TestOutgoingNetworkTransport);
- }
-
- public void testProtocolSpecificOverriddenOutgoingTransportForv0_8() throws Exception
- {
- setTestSystemProperty(Transport.QPID_TRANSPORT_V0_8_PROPNAME, TestOutgoingNetworkTransport.class.getName());
-
- final OutgoingNetworkTransport networkTransport = Transport.getOutgoingTransportInstance(ProtocolVersion.v8_0);
- assertNotNull(networkTransport);
- assertTrue(networkTransport instanceof TestOutgoingNetworkTransport);
- }
-
- public void testDefaultGetOutgoingTransportForv0_10() throws Exception
- {
- final OutgoingNetworkTransport networkTransport = Transport.getOutgoingTransportInstance(ProtocolVersion.v0_10);
- assertNotNull(networkTransport);
- assertTrue(networkTransport instanceof IoNetworkTransport);
- }
-
- public void testDefaultGetIncomingTransport() throws Exception
- {
- final IncomingNetworkTransport networkTransport = Transport.getIncomingTransportInstance();
- assertNotNull(networkTransport);
- assertTrue(networkTransport instanceof IoNetworkTransport);
- }
-
- public void testOverriddenGetIncomingTransport() throws Exception
- {
- setTestSystemProperty(Transport.QPID_BROKER_TRANSPORT_PROPNAME, TestIncomingNetworkTransport.class.getName());
-
- final IncomingNetworkTransport networkTransport = Transport.getIncomingTransportInstance();
- assertNotNull(networkTransport);
- assertTrue(networkTransport instanceof TestIncomingNetworkTransport);
- }
-
- public void testInvalidOutgoingTransportClassName() throws Exception
- {
- setTestSystemProperty(Transport.QPID_TRANSPORT_PROPNAME, "invalid");
-
- try
- {
- Transport.getOutgoingTransportInstance(ProtocolVersion.v0_10);
- fail("Should have failed to load the invalid class");
- }
- catch(TransportException te)
- {
- //expected, ignore
- }
- }
-
- public void testInvalidOutgoingTransportProtocolVersion() throws Exception
- {
- try
- {
- Transport.getOutgoingTransportInstance(new ProtocolVersion((byte)0, (byte)0));
- fail("Should have failed to load the transport for invalid protocol version");
- }
- catch(IllegalArgumentException iae)
- {
- //expected, ignore
- }
- }
-
- public static class TestOutgoingNetworkTransport implements OutgoingNetworkTransport
- {
-
- public void close()
- {
- throw new UnsupportedOperationException();
- }
-
- public NetworkConnection getConnection()
- {
- throw new UnsupportedOperationException();
- }
-
- public NetworkConnection connect(ConnectionSettings settings,
- Receiver<ByteBuffer> delegate, SSLContext sslContext)
- {
- throw new UnsupportedOperationException();
- }
- }
-
- public static class TestIncomingNetworkTransport implements IncomingNetworkTransport
- {
-
- public void close()
- {
- throw new UnsupportedOperationException();
- }
-
- public NetworkConnection getConnection()
- {
- throw new UnsupportedOperationException();
- }
-
- public void accept(NetworkTransportConfiguration config,
- ProtocolEngineFactory factory, SSLContext sslContext)
- {
- throw new UnsupportedOperationException();
- }
- }
-}
diff --git a/java/common/src/test/java/org/apache/qpid/transport/network/io/IoTransport.java b/java/common/src/test/java/org/apache/qpid/transport/network/io/IoTransport.java
deleted file mode 100644
index 215c6d9931..0000000000
--- a/java/common/src/test/java/org/apache/qpid/transport/network/io/IoTransport.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.qpid.transport.network.io;
-
-import java.net.Socket;
-import java.nio.ByteBuffer;
-
-import org.apache.qpid.transport.Binding;
-import org.apache.qpid.transport.Sender;
-import org.apache.qpid.transport.util.Logger;
-
-/**
- * This class provides a socket based transport using the java.io
- * classes.
- *
- * The following params are configurable via JVM arguments
- * TCP_NO_DELAY - amqj.tcpNoDelay
- * SO_RCVBUF - amqj.receiveBufferSize
- * SO_SNDBUF - amqj.sendBufferSize
- */
-public final class IoTransport<E>
-{
-
-
- private static final Logger log = Logger.get(IoTransport.class);
-
- private static int DEFAULT_READ_WRITE_BUFFER_SIZE = 64 * 1024;
- private static int readBufferSize = Integer.getInteger
- ("amqj.receiveBufferSize", DEFAULT_READ_WRITE_BUFFER_SIZE);
- private static int writeBufferSize = Integer.getInteger
- ("amqj.sendBufferSize", DEFAULT_READ_WRITE_BUFFER_SIZE);
-
- private Socket socket;
- private Sender<ByteBuffer> sender;
- private E endpoint;
- private IoReceiver receiver;
- private long timeout = 60000;
-
- IoTransport(Socket socket, Binding<E,ByteBuffer> binding)
- {
- this.socket = socket;
- setupTransport(socket, binding);
- }
-
- private void setupTransport(Socket socket, Binding<E, ByteBuffer> binding)
- {
- IoSender ios = new IoSender(socket, 2*writeBufferSize, timeout);
- ios.initiate();
-
- this.sender = ios;
- this.endpoint = binding.endpoint(sender);
- this.receiver = new IoReceiver(socket, binding.receiver(endpoint),
- 2*readBufferSize, timeout);
- this.receiver.initiate();
-
- ios.registerCloseListener(this.receiver);
- }
-
- public Sender<ByteBuffer> getSender()
- {
- return sender;
- }
-
- public IoReceiver getReceiver()
- {
- return receiver;
- }
-
- public Socket getSocket()
- {
- return socket;
- }
-
-}
diff --git a/java/common/src/test/java/org/apache/qpid/transport/network/mina/MINANetworkDriverTest.java b/java/common/src/test/java/org/apache/qpid/transport/network/mina/MINANetworkDriverTest.java
new file mode 100644
index 0000000000..fc8e689ca4
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/transport/network/mina/MINANetworkDriverTest.java
@@ -0,0 +1,494 @@
+/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.qpid.transport.network.mina;
+
+import java.net.BindException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.UnknownHostException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.framing.AMQDataBlock;
+import org.apache.qpid.protocol.ProtocolEngine;
+import org.apache.qpid.protocol.ProtocolEngineFactory;
+import org.apache.qpid.transport.NetworkDriver;
+import org.apache.qpid.transport.OpenException;
+
+public class MINANetworkDriverTest extends TestCase
+{
+
+ private static final String TEST_DATA = "YHALOTHAR";
+ private static int TEST_PORT = 2323;
+ private NetworkDriver _server;
+ private NetworkDriver _client;
+ private CountingProtocolEngine _countingEngine; // Keeps a count of how many bytes it's read
+ private Exception _thrownEx;
+
+ @Override
+ public void setUp()
+ {
+ _server = new MINANetworkDriver();
+ _client = new MINANetworkDriver();
+ _thrownEx = null;
+ _countingEngine = new CountingProtocolEngine();
+ // increment the port to prevent tests clashing with each other when
+ // the port is in TIMED_WAIT state.
+ TEST_PORT++;
+ }
+
+ @Override
+ public void tearDown()
+ {
+ if (_server != null)
+ {
+ _server.close();
+ }
+
+ if (_client != null)
+ {
+ _client.close();
+ }
+ }
+
+ /**
+ * Tests that a socket can't be opened if a driver hasn't been bound
+ * to the port and can be opened if a driver has been bound.
+ * @throws BindException
+ * @throws UnknownHostException
+ * @throws OpenException
+ */
+ public void testBindOpen() throws BindException, UnknownHostException, OpenException
+ {
+ try
+ {
+ _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null);
+ }
+ catch (OpenException e)
+ {
+ _thrownEx = e;
+ }
+
+ assertNotNull("Open should have failed since no engine bound", _thrownEx);
+
+ _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null);
+
+ _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null);
+ }
+
+ /**
+ * Tests that a socket can't be opened after a bound NetworkDriver has been closed
+ * @throws BindException
+ * @throws UnknownHostException
+ * @throws OpenException
+ */
+ public void testBindOpenCloseOpen() throws BindException, UnknownHostException, OpenException
+ {
+ _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null);
+ _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null);
+ _client.close();
+ _server.close();
+
+ try
+ {
+ _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null);
+ }
+ catch (OpenException e)
+ {
+ _thrownEx = e;
+ }
+ assertNotNull("Open should have failed", _thrownEx);
+ }
+
+ /**
+ * Checks that the right exception is thrown when binding a NetworkDriver to an already
+ * existing socket.
+ */
+ public void testBindPortInUse()
+ {
+ try
+ {
+ _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null);
+ }
+ catch (BindException e)
+ {
+ fail("First bind should not fail");
+ }
+
+ try
+ {
+ _client.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null);
+ }
+ catch (BindException e)
+ {
+ _thrownEx = e;
+ }
+ assertNotNull("Second bind should throw BindException", _thrownEx);
+ }
+
+ /**
+ * tests that bytes sent on a network driver are received at the other end
+ *
+ * @throws UnknownHostException
+ * @throws OpenException
+ * @throws InterruptedException
+ * @throws BindException
+ */
+ public void testSend() throws UnknownHostException, OpenException, InterruptedException, BindException
+ {
+ // Open a connection from a counting engine to an echo engine
+ _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null);
+ _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null);
+
+ // Tell the counting engine how much data we're sending
+ _countingEngine.setNewLatch(TEST_DATA.getBytes().length);
+
+ // Send the data and wait for up to 2 seconds to get it back
+ _client.send(ByteBuffer.wrap(TEST_DATA.getBytes()));
+ _countingEngine.getLatch().await(2, TimeUnit.SECONDS);
+
+ // Check what we got
+ assertEquals("Wrong amount of data recieved", TEST_DATA.getBytes().length, _countingEngine.getReadBytes());
+ }
+
+ /**
+ * Opens a connection with a low read idle and check that it gets triggered
+ * @throws BindException
+ * @throws OpenException
+ * @throws UnknownHostException
+ *
+ */
+ public void testSetReadIdle() throws BindException, UnknownHostException, OpenException
+ {
+ // Open a connection from a counting engine to an echo engine
+ _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null);
+ _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null);
+ assertFalse("Reader should not have been idle", _countingEngine.getReaderHasBeenIdle());
+ _client.setMaxReadIdle(1);
+ sleepForAtLeast(1500);
+ assertTrue("Reader should have been idle", _countingEngine.getReaderHasBeenIdle());
+ }
+
+ /**
+ * Opens a connection with a low write idle and check that it gets triggered
+ * @throws BindException
+ * @throws OpenException
+ * @throws UnknownHostException
+ *
+ */
+ public void testSetWriteIdle() throws BindException, UnknownHostException, OpenException
+ {
+ // Open a connection from a counting engine to an echo engine
+ _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null);
+ _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null);
+ assertFalse("Reader should not have been idle", _countingEngine.getWriterHasBeenIdle());
+ _client.setMaxWriteIdle(1);
+ sleepForAtLeast(1500);
+ assertTrue("Reader should have been idle", _countingEngine.getWriterHasBeenIdle());
+ }
+
+
+ /**
+ * Creates and then closes a connection from client to server and checks that the server
+ * has its closed() method called. Then creates a new client and closes the server to check
+ * that the client has its closed() method called.
+ * @throws BindException
+ * @throws UnknownHostException
+ * @throws OpenException
+ */
+ public void testClosed() throws BindException, UnknownHostException, OpenException
+ {
+ // Open a connection from a counting engine to an echo engine
+ EchoProtocolEngineSingletonFactory factory = new EchoProtocolEngineSingletonFactory();
+ _server.bind(TEST_PORT, null, factory, null, null);
+ _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null);
+ EchoProtocolEngine serverEngine = null;
+ while (serverEngine == null)
+ {
+ serverEngine = factory.getEngine();
+ if (serverEngine == null)
+ {
+ try
+ {
+ Thread.sleep(10);
+ }
+ catch (InterruptedException e)
+ {
+ }
+ }
+ }
+ assertFalse("Server should not have been closed", serverEngine.getClosed());
+ serverEngine.setNewLatch(1);
+ _client.close();
+ try
+ {
+ serverEngine.getLatch().await(2, TimeUnit.SECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ }
+ assertTrue("Server should have been closed", serverEngine.getClosed());
+
+ _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null);
+ _countingEngine.setClosed(false);
+ assertFalse("Client should not have been closed", _countingEngine.getClosed());
+ _countingEngine.setNewLatch(1);
+ _server.close();
+ try
+ {
+ _countingEngine.getLatch().await(2, TimeUnit.SECONDS);
+ }
+ catch (InterruptedException e)
+ {
+ }
+ assertTrue("Client should have been closed", _countingEngine.getClosed());
+ }
+
+ /**
+ * Create a connection and instruct the client to throw an exception when it gets some data
+ * and that the latch gets counted down.
+ * @throws BindException
+ * @throws UnknownHostException
+ * @throws OpenException
+ * @throws InterruptedException
+ */
+ public void testExceptionCaught() throws BindException, UnknownHostException, OpenException, InterruptedException
+ {
+ _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null);
+ _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null);
+
+
+ assertEquals("Exception should not have been thrown", 1,
+ _countingEngine.getExceptionLatch().getCount());
+ _countingEngine.setErrorOnNextRead(true);
+ _countingEngine.setNewLatch(TEST_DATA.getBytes().length);
+ _client.send(ByteBuffer.wrap(TEST_DATA.getBytes()));
+ _countingEngine.getExceptionLatch().await(2, TimeUnit.SECONDS);
+ assertEquals("Exception should have been thrown", 0,
+ _countingEngine.getExceptionLatch().getCount());
+ }
+
+ /**
+ * Opens a connection and checks that the remote address is the one that was asked for
+ * @throws BindException
+ * @throws UnknownHostException
+ * @throws OpenException
+ */
+ public void testGetRemoteAddress() throws BindException, UnknownHostException, OpenException
+ {
+ _server.bind(TEST_PORT, null, new EchoProtocolEngineSingletonFactory(), null, null);
+ _client.open(TEST_PORT, InetAddress.getLocalHost(), _countingEngine, null, null);
+ assertEquals(new InetSocketAddress(InetAddress.getLocalHost(), TEST_PORT),
+ _client.getRemoteAddress());
+ }
+
+ private class EchoProtocolEngineSingletonFactory implements ProtocolEngineFactory
+ {
+ EchoProtocolEngine _engine = null;
+
+ public ProtocolEngine newProtocolEngine(NetworkDriver driver)
+ {
+ if (_engine == null)
+ {
+ _engine = new EchoProtocolEngine();
+ _engine.setNetworkDriver(driver);
+ }
+ return getEngine();
+ }
+
+ public EchoProtocolEngine getEngine()
+ {
+ return _engine;
+ }
+ }
+
+ public class CountingProtocolEngine implements ProtocolEngine
+ {
+
+ protected NetworkDriver _driver;
+ public ArrayList<ByteBuffer> _receivedBytes = new ArrayList<ByteBuffer>();
+ private int _readBytes;
+ private CountDownLatch _latch = new CountDownLatch(0);
+ private boolean _readerHasBeenIdle;
+ private boolean _writerHasBeenIdle;
+ private boolean _closed = false;
+ private boolean _nextReadErrors = false;
+ private CountDownLatch _exceptionLatch = new CountDownLatch(1);
+
+ public void closed()
+ {
+ setClosed(true);
+ _latch.countDown();
+ }
+
+ public void setErrorOnNextRead(boolean b)
+ {
+ _nextReadErrors = b;
+ }
+
+ public void setNewLatch(int length)
+ {
+ _latch = new CountDownLatch(length);
+ }
+
+ public long getReadBytes()
+ {
+ return _readBytes;
+ }
+
+ public SocketAddress getRemoteAddress()
+ {
+ if (_driver != null)
+ {
+ return _driver.getRemoteAddress();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public SocketAddress getLocalAddress()
+ {
+ if (_driver != null)
+ {
+ return _driver.getLocalAddress();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public long getWrittenBytes()
+ {
+ return 0;
+ }
+
+ public void readerIdle()
+ {
+ _readerHasBeenIdle = true;
+ }
+
+ public void setNetworkDriver(NetworkDriver driver)
+ {
+ _driver = driver;
+ }
+
+ public void writeFrame(AMQDataBlock frame)
+ {
+
+ }
+
+ public void writerIdle()
+ {
+ _writerHasBeenIdle = true;
+ }
+
+ public void exception(Throwable t)
+ {
+ _exceptionLatch.countDown();
+ }
+
+ public CountDownLatch getExceptionLatch()
+ {
+ return _exceptionLatch;
+ }
+
+ public void received(ByteBuffer msg)
+ {
+ // increment read bytes and count down the latch for that many
+ int bytes = msg.remaining();
+ _readBytes += bytes;
+ for (int i = 0; i < bytes; i++)
+ {
+ _latch.countDown();
+ }
+
+ // Throw an error if we've been asked too, but we can still count
+ if (_nextReadErrors)
+ {
+ throw new RuntimeException("Was asked to error");
+ }
+ }
+
+ public CountDownLatch getLatch()
+ {
+ return _latch;
+ }
+
+ public boolean getWriterHasBeenIdle()
+ {
+ return _writerHasBeenIdle;
+ }
+
+ public boolean getReaderHasBeenIdle()
+ {
+ return _readerHasBeenIdle;
+ }
+
+ public void setClosed(boolean _closed)
+ {
+ this._closed = _closed;
+ }
+
+ public boolean getClosed()
+ {
+ return _closed;
+ }
+
+ }
+
+ private class EchoProtocolEngine extends CountingProtocolEngine
+ {
+
+ public void received(ByteBuffer msg)
+ {
+ super.received(msg);
+ msg.rewind();
+ _driver.send(msg);
+ }
+ }
+
+ public static void sleepForAtLeast(long period)
+ {
+ long start = System.currentTimeMillis();
+ long timeLeft = period;
+ while (timeLeft > 0)
+ {
+ try
+ {
+ Thread.sleep(timeLeft);
+ }
+ catch (InterruptedException e)
+ {
+ // Ignore it
+ }
+ timeLeft = period - (System.currentTimeMillis() - start);
+ }
+ }
+} \ No newline at end of file
diff --git a/java/common/src/test/java/org/apache/qpid/util/FileUtilsTest.java b/java/common/src/test/java/org/apache/qpid/util/FileUtilsTest.java
index d6767eb9c0..7eba5f092e 100644
--- a/java/common/src/test/java/org/apache/qpid/util/FileUtilsTest.java
+++ b/java/common/src/test/java/org/apache/qpid/util/FileUtilsTest.java
@@ -27,9 +27,7 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
-import java.io.InputStream;
import java.util.List;
-import java.util.Properties;
public class FileUtilsTest extends TestCase
{
@@ -184,20 +182,6 @@ public class FileUtilsTest extends TestCase
}
}
-
- /**
- * Helper method to create a temporary file with test content.
- *
- * @param test_data The data to store in the file
- *
- * @return The File reference
- */
- private File createTestFileInTmpDir(final String testData) throws Exception
- {
- final File tmpFile = File.createTempFile("test", "tmp");
-
- return createTestFile(tmpFile.getCanonicalPath(), testData);
- }
/**
* Helper method to create a test file with a string content
*
@@ -318,74 +302,8 @@ public class FileUtilsTest extends TestCase
// expected path
}
}
-
- /**
- * Tests that openFileOrDefaultResource can open a file on the filesystem.
- *
- */
- public void testOpenFileOrDefaultResourceOpensFileOnFileSystem() throws Exception
- {
- final File testFile = createTestFileInTmpDir("src=tmpfile");
- final String filenameOnFilesystem = testFile.getCanonicalPath();
- final String defaultResource = "org/apache/qpid/util/default.properties";
-
-
- final InputStream is = FileUtils.openFileOrDefaultResource(filenameOnFilesystem, defaultResource, this.getClass().getClassLoader());
- assertNotNull("Stream must not be null", is);
- final Properties p = new Properties();
- p.load(is);
- assertEquals("tmpfile", p.getProperty("src"));
- }
/**
- * Tests that openFileOrDefaultResource can open a file on the classpath.
- *
- */
- public void testOpenFileOrDefaultResourceOpensFileOnClasspath() throws Exception
- {
- final String mydefaultsResource = "org/apache/qpid/util/mydefaults.properties";
- final String defaultResource = "org/apache/qpid/util/default.properties";
-
-
- final InputStream is = FileUtils.openFileOrDefaultResource(mydefaultsResource, defaultResource, this.getClass().getClassLoader());
- assertNotNull("Stream must not be null", is);
- final Properties p = new Properties();
- p.load(is);
- assertEquals("mydefaults", p.getProperty("src"));
- }
-
- /**
- * Tests that openFileOrDefaultResource returns the default resource when file cannot be found.
- */
- public void testOpenFileOrDefaultResourceOpensDefaultResource() throws Exception
- {
- final File fileThatDoesNotExist = new File("/does/not/exist.properties");
- assertFalse("Test must not exist", fileThatDoesNotExist.exists());
-
- final String defaultResource = "org/apache/qpid/util/default.properties";
-
- final InputStream is = FileUtils.openFileOrDefaultResource(fileThatDoesNotExist.getCanonicalPath(), defaultResource, this.getClass().getClassLoader());
- assertNotNull("Stream must not be null", is);
- Properties p = new Properties();
- p.load(is);
- assertEquals("default.properties", p.getProperty("src"));
- }
-
- /**
- * Tests that openFileOrDefaultResource returns null if neither the file nor
- * the default resource can be found..
- */
- public void testOpenFileOrDefaultResourceReturnsNullWhenNeitherCanBeFound() throws Exception
- {
-
- final String mydefaultsResource = "org/apache/qpid/util/doesnotexisteiether.properties";
- final String defaultResource = "org/apache/qpid/util/doesnotexisteiether.properties";
-
- final InputStream is = FileUtils.openFileOrDefaultResource(mydefaultsResource, defaultResource, this.getClass().getClassLoader());
- assertNull("Stream must be null", is);
- }
-
- /**
* Given two lists of File arrays ensure they are the same length and all entries in Before are in After
*
* @param filesBefore File[]
diff --git a/java/common/src/test/java/org/apache/qpid/util/default.properties b/java/common/src/test/java/org/apache/qpid/util/default.properties
deleted file mode 100644
index cb522ea9a7..0000000000
--- a/java/common/src/test/java/org/apache/qpid/util/default.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-# Used by FileUtilsTests
-src=default.properties \ No newline at end of file
diff --git a/java/common/src/test/java/org/apache/qpid/util/mydefaults.properties b/java/common/src/test/java/org/apache/qpid/util/mydefaults.properties
deleted file mode 100644
index 6a49d927d0..0000000000
--- a/java/common/src/test/java/org/apache/qpid/util/mydefaults.properties
+++ /dev/null
@@ -1,2 +0,0 @@
-# Used by FileUtilsTests
-src=mydefaults \ No newline at end of file
diff --git a/java/common/templates/method/version/MethodBodyClass.vm b/java/common/templates/method/version/MethodBodyClass.vm
index ce8a453eeb..a739110d70 100644
--- a/java/common/templates/method/version/MethodBodyClass.vm
+++ b/java/common/templates/method/version/MethodBodyClass.vm
@@ -46,11 +46,9 @@
package org.apache.qpid.framing.amqp_$version.getMajor()_$version.getMinor();
-import java.io.DataInputStream;
-import java.io.DataOutputStream;
-import java.io.IOException;
import java.util.HashMap;
+import org.apache.mina.common.ByteBuffer;
import org.apache.qpid.framing.*;
import org.apache.qpid.AMQException;
@@ -58,7 +56,7 @@ public class ${javaClassName} extends AMQMethodBody_$version.getMajor()_$version
{
private static final AMQMethodBodyInstanceFactory FACTORY_INSTANCE = new AMQMethodBodyInstanceFactory()
{
- public AMQMethodBody newInstance(DataInputStream in, long size) throws AMQFrameDecodingException, IOException
+ public AMQMethodBody newInstance(ByteBuffer in, long size) throws AMQFrameDecodingException
{
return new ${javaClassName}(in);
}
@@ -86,7 +84,7 @@ public class ${javaClassName} extends AMQMethodBody_$version.getMajor()_$version
// Constructor
- public ${javaClassName}(DataInputStream buffer) throws AMQFrameDecodingException, IOException
+ public ${javaClassName}(ByteBuffer buffer) throws AMQFrameDecodingException
{
#foreach( $field in $method.ConsolidatedFields )
_$field.Name = read$field.getEncodingType()( buffer );
@@ -171,7 +169,7 @@ public class ${javaClassName} extends AMQMethodBody_$version.getMajor()_$version
return size;
}
- public void writeMethodPayload(DataOutputStream buffer) throws IOException
+ public void writeMethodPayload(ByteBuffer buffer)
{
#foreach( $field in $method.ConsolidatedFields )
write$field.getEncodingType()( buffer, _$field.Name );
diff --git a/java/common/templates/model/MethodRegistryClass.vm b/java/common/templates/model/MethodRegistryClass.vm
index 8258175ce7..759e5e4a42 100644
--- a/java/common/templates/model/MethodRegistryClass.vm
+++ b/java/common/templates/model/MethodRegistryClass.vm
@@ -30,8 +30,7 @@
package org.apache.qpid.framing;
-import java.io.DataInputStream;
-import java.io.IOException;
+import org.apache.mina.common.ByteBuffer;
import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter;
@@ -54,8 +53,8 @@ public abstract class MethodRegistry
#end
- public abstract AMQMethodBody convertToBody(DataInputStream in, long size)
- throws AMQFrameDecodingException, IOException;
+ public abstract AMQMethodBody convertToBody(ByteBuffer in, long size)
+ throws AMQFrameDecodingException;
public abstract int getMaxClassId();
@@ -102,4 +101,4 @@ public abstract class MethodRegistry
public abstract ProtocolVersionMethodConverter getProtocolVersionMethodConverter();
-}
+} \ No newline at end of file
diff --git a/java/common/templates/model/version/MethodRegistryClass.vm b/java/common/templates/model/version/MethodRegistryClass.vm
index 79553f7748..277605e34b 100644
--- a/java/common/templates/model/version/MethodRegistryClass.vm
+++ b/java/common/templates/model/version/MethodRegistryClass.vm
@@ -35,33 +35,32 @@ import org.apache.qpid.protocol.AMQConstant;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.DataInputStream;
-import java.io.IOException;
+import org.apache.mina.common.ByteBuffer;
import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter;
public class MethodRegistry_$version.getMajor()_$version.getMinor() extends MethodRegistry
{
-
+
private static final Logger _log = LoggerFactory.getLogger(MethodRegistry.class);
- private ProtocolVersionMethodConverter _protocolVersionConverter = new MethodConverter_$version.getMajor()_$version.getMinor()();
-
-#set( $specificModel = $model.asSingleVersionModel() )
-
-
-#set( $maxClassId = $specificModel.getMaximumClassId()+1 )
- private final AMQMethodBodyInstanceFactory[][] _factories = new AMQMethodBodyInstanceFactory[$maxClassId][];
-
- public MethodRegistry_$version.getMajor()_$version.getMinor()()
- {
- this(new ProtocolVersion((byte)$version.getMajor(),(byte)$version.getMinor()));
+ private ProtocolVersionMethodConverter _protocolVersionConverter = new MethodConverter_$version.getMajor()_$version.getMinor()();
+
+#set( $specificModel = $model.asSingleVersionModel() )
+
+
+#set( $maxClassId = $specificModel.getMaximumClassId()+1 )
+ private final AMQMethodBodyInstanceFactory[][] _factories = new AMQMethodBodyInstanceFactory[$maxClassId][];
+
+ public MethodRegistry_$version.getMajor()_$version.getMinor()()
+ {
+ this(new ProtocolVersion((byte)$version.getMajor(),(byte)$version.getMinor()));
}
-
- public MethodRegistry_$version.getMajor()_$version.getMinor()(ProtocolVersion pv)
- {
- super(pv);
+
+ public MethodRegistry_$version.getMajor()_$version.getMinor()(ProtocolVersion pv)
+ {
+ super(pv);
#foreach( $amqpClass in $specificModel.getClassList() )
#set( $amqpClassNameFirstChar = $amqpClass.getName().substring(0,1) )
#set( $amqpClassNameFirstCharU = $amqpClassNameFirstChar.toUpperCase() )
@@ -69,30 +68,30 @@ public class MethodRegistry_$version.getMajor()_$version.getMinor() extends Meth
- // Register method body instance factories for the $amqpClassNameUpperCamel class.
+ // Register method body instance factories for the $amqpClassNameUpperCamel class.
-#set( $maxMethodId = $amqpClass.getMaximumMethodId()+1 )
+#set( $maxMethodId = $amqpClass.getMaximumMethodId()+1 )
_factories[$amqpClass.getClassId()] = new AMQMethodBodyInstanceFactory[$maxMethodId];
-
+
#foreach( $amqpMethod in $amqpClass.getMethodList() )
#set( $amqpMethodNameFirstChar = $amqpMethod.getName().substring(0,1) )
#set( $amqpMethodNameFirstCharU = $amqpMethodNameFirstChar.toUpperCase() )
#set( $amqpMethodNameUpperCamel = "$amqpMethodNameFirstCharU$amqpMethod.getName().substring(1)" )
_factories[$amqpClass.getClassId()][$amqpMethod.getMethodId()] = ${amqpClassNameUpperCamel}${amqpMethodNameUpperCamel}BodyImpl.getFactory();
-#end
-
+#end
+
#end
-
-
- }
+
+
+ }
- public AMQMethodBody convertToBody(DataInputStream in, long size)
- throws AMQFrameDecodingException, IOException
+ public AMQMethodBody convertToBody(ByteBuffer in, long size)
+ throws AMQFrameDecodingException
{
- int classId = in.readUnsignedShort();
- int methodId = in.readUnsignedShort();
-
+ int classId = in.getUnsignedShort();
+ int methodId = in.getUnsignedShort();
+
AMQMethodBodyInstanceFactory bodyFactory;
try
{
@@ -138,15 +137,15 @@ public class MethodRegistry_$version.getMajor()_$version.getMinor() extends Meth
public int getMaxClassId()
- {
- return $specificModel.getMaximumClassId();
- }
+ {
+ return $specificModel.getMaximumClassId();
+ }
public int getMaxMethodId(int classId)
- {
- return _factories[classId].length - 1;
- }
-
+ {
+ return _factories[classId].length - 1;
+ }
+
#foreach( $amqpClass in $specificModel.getClassList() )
@@ -154,12 +153,12 @@ public class MethodRegistry_$version.getMajor()_$version.getMinor() extends Meth
#set( $amqpClassNameFirstCharU = $amqpClassNameFirstChar.toUpperCase() )
#set( $amqpClassNameUpperCamel = "$amqpClassNameFirstCharU$amqpClass.getName().substring(1)" )
-
+
#foreach( $amqpMethod in $amqpClass.getMethodList() )
#set( $amqpMethodNameFirstChar = $amqpMethod.getName().substring(0,1) )
#set( $amqpMethodNameFirstCharU = $amqpMethodNameFirstChar.toUpperCase() )
#set( $amqpMethodNameUpperCamel = "$amqpMethodNameFirstCharU$amqpMethod.getName().substring(1)" )
- public ${amqpClassNameUpperCamel}${amqpMethodNameUpperCamel}Body create${amqpClassNameUpperCamel}${amqpMethodNameUpperCamel}Body(
+ public ${amqpClassNameUpperCamel}${amqpMethodNameUpperCamel}Body create${amqpClassNameUpperCamel}${amqpMethodNameUpperCamel}Body(
#foreach( $field in $amqpMethod.FieldList )
#if( $velocityCount == $amqpMethod.getFieldList().size() )
final $field.NativeType $field.Name
@@ -167,9 +166,9 @@ public class MethodRegistry_$version.getMajor()_$version.getMinor() extends Meth
final $field.NativeType $field.Name,
#end
#end
- )
+ )
{
- return new ${amqpClassNameUpperCamel}${amqpMethodNameUpperCamel}BodyImpl(
+ return new ${amqpClassNameUpperCamel}${amqpMethodNameUpperCamel}BodyImpl(
#foreach( $field in $amqpMethod.FieldList )
#if( $velocityCount == $amqpMethod.getFieldList().size() )
$field.Name
@@ -177,18 +176,18 @@ public class MethodRegistry_$version.getMajor()_$version.getMinor() extends Meth
$field.Name,
#end
#end
- );
+ );
}
-#end
-
+#end
+
#end
-
-
+
+
public ProtocolVersionMethodConverter getProtocolVersionMethodConverter()
{
return _protocolVersionConverter;
- }
+ }
}