summaryrefslogtreecommitdiff
path: root/java/common
diff options
context:
space:
mode:
Diffstat (limited to 'java/common')
-rw-r--r--java/common/Composite.tpl77
-rw-r--r--java/common/Constant.tpl23
-rw-r--r--java/common/Enum.tpl23
-rw-r--r--java/common/Invoker.tpl52
-rw-r--r--java/common/MethodDelegate.tpl29
-rw-r--r--java/common/Option.tpl44
-rw-r--r--java/common/StructFactory.tpl23
-rw-r--r--java/common/Type.tpl23
-rwxr-xr-xjava/common/bin/qpid-run9
-rw-r--r--java/common/build.xml79
-rwxr-xr-xjava/common/codegen45
-rw-r--r--java/common/genutil.py19
-rw-r--r--java/common/jython-2.2-rc2.jarbin1203486 -> 0 bytes
-rw-r--r--java/common/jython-lib.jarbin1570006 -> 0 bytes
-rw-r--r--java/common/pom.xml187
-rw-r--r--java/common/protocol-version.xml4
-rwxr-xr-xjava/common/src/main/java/common.bnd6
-rw-r--r--java/common/src/main/java/org/apache/qpid/AMQConnectionException.java2
-rw-r--r--java/common/src/main/java/org/apache/qpid/AMQException.java29
-rw-r--r--java/common/src/main/java/org/apache/qpid/BrokerDetails.java138
-rw-r--r--java/common/src/main/java/org/apache/qpid/BrokerDetailsImpl.java264
-rw-r--r--java/common/src/main/java/org/apache/qpid/ConsoleOutput.java12
-rw-r--r--java/common/src/main/java/org/apache/qpid/ErrorCode.java23
-rw-r--r--java/common/src/main/java/org/apache/qpid/QpidConfig.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/SecurityHelper.java71
-rw-r--r--java/common/src/main/java/org/apache/qpid/SerialException.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/ToyBroker.java11
-rw-r--r--java/common/src/main/java/org/apache/qpid/ToyClient.java44
-rw-r--r--java/common/src/main/java/org/apache/qpid/ToyExchange.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/codec/AMQCodecFactory.java7
-rw-r--r--java/common/src/main/java/org/apache/qpid/codec/AMQDecoder.java79
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java39
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockEncoder.java2
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQMethodBodyImpl.java162
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/AMQTypedValue.java63
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/BasicContentHeaderProperties.java4
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/FieldTable.java33
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/ProtocolInitiation.java50
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/abstraction/MessagePublishInfoImpl.java85
-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/AMQMethodBody_0_9.java174
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/MethodConverter_0_9.java52
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/amqp_0_91/AMQMethodBody_0_91.java37
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/amqp_0_91/MethodConverter_0_91.java132
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/AMQMethodBody_8_0.java169
-rw-r--r--java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/MethodConverter_8_0.java50
-rw-r--r--java/common/src/main/java/org/apache/qpid/pool/Event.java155
-rw-r--r--java/common/src/main/java/org/apache/qpid/pool/Job.java139
-rw-r--r--java/common/src/main/java/org/apache/qpid/pool/PoolingFilter.java491
-rw-r--r--java/common/src/main/java/org/apache/qpid/pool/ReadWriteRunnable.java1
-rw-r--r--java/common/src/main/java/org/apache/qpid/pool/ReadWriteThreadModel.java102
-rw-r--r--java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java9
-rw-r--r--java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngine.java61
-rw-r--r--java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngineFactory.java31
-rw-r--r--java/common/src/main/java/org/apache/qpid/security/CallbackHandlerRegistry.java94
-rw-r--r--java/common/src/main/java/org/apache/qpid/security/DynamicSaslRegistrar.java74
-rw-r--r--java/common/src/main/java/org/apache/qpid/security/amqplain/AmqPlainSaslClient.java105
-rw-r--r--java/common/src/main/java/org/apache/qpid/security/amqplain/AmqPlainSaslClientFactory.java62
-rw-r--r--java/common/src/main/java/org/apache/qpid/ssl/SSLContextFactory.java92
-rw-r--r--java/common/src/main/java/org/apache/qpid/thread/DefaultThreadFactory.java18
-rw-r--r--java/common/src/main/java/org/apache/qpid/thread/QpidThreadExecutor.java (renamed from java/common/src/main/java/org/apache/qpid/security/JCAProvider.java)36
-rw-r--r--java/common/src/main/java/org/apache/qpid/thread/RealtimeThreadFactory.java47
-rw-r--r--java/common/src/main/java/org/apache/qpid/thread/ThreadFactory.java7
-rw-r--r--java/common/src/main/java/org/apache/qpid/thread/Threading.java26
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Binary.java16
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Channel.java176
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ClientDelegate.java139
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Connection.java435
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ConnectionDelegate.java246
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ConnectionException.java31
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ConnectionListener.java38
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Echo.java37
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Method.java71
-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.java44
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/OpenException.java34
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ProtocolHeader.java8
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ProtocolVersionException.java16
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ProtocolViolationException.java35
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/RangeSet.java5
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Sender.java1
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/SenderException.java (renamed from java/common/src/main/java/org/apache/qpid/transport/ChannelDelegate.java)28
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java183
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Session.java641
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/SessionClosedException.java12
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/SessionDelegate.java87
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/SessionException.java29
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/SessionListener.java42
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Sink.java37
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/Struct.java2
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/TransportException.java5
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/codec/BBDecoder.java58
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/codec/BBEncoder.java112
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/codec/Decoder.java227
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/codec/Encodable.java19
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/codec/Encoder.java230
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/Assembler.java5
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/ConnectionBinding.java39
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java37
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/InputHandler.java5
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/InputHandler_0_9.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/IoAcceptor.java13
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/IoReceiver.java52
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/IoSender.java78
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/io/IoTransport.java87
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java421
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaHandler.java4
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/mina/MinaSender.java13
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/nio/NioHandler.java26
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/nio/NioSender.java26
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/ssl/SSLReceiver.java184
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/network/ssl/SSLSender.java255
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/util/Functions.java13
-rw-r--r--java/common/src/main/java/org/apache/qpid/transport/util/Waiter.java63
-rw-r--r--java/common/src/main/java/org/apache/qpid/url/BindingURLImpl.java261
-rw-r--r--java/common/src/main/java/org/apache/qpid/url/BindingURLParser.java25
-rw-r--r--java/common/src/main/java/org/apache/qpid/url/QpidBindingURL.java53
-rw-r--r--java/common/src/main/java/org/apache/qpid/url/QpidURL.java57
-rw-r--r--java/common/src/main/java/org/apache/qpid/url/QpidURLImpl.java460
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/FileUtils.java220
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/NetMatcher.java264
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/PropertiesUtils.java200
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/Serial.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/Strings.java156
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/concurrent/AlreadyUnblockedException.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/concurrent/BatchSynchQueue.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/concurrent/BatchSynchQueueBase.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/concurrent/BooleanLatch.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/concurrent/Capacity.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/concurrent/SynchBuffer.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/concurrent/SynchException.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/concurrent/SynchQueue.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/concurrent/SynchRecord.java21
-rw-r--r--java/common/src/main/java/org/apache/qpid/util/concurrent/SynchRef.java21
-rw-r--r--java/common/src/test/java/org/apache/qpid/AMQExceptionTest.java106
-rw-r--r--java/common/src/test/java/org/apache/qpid/codec/AMQDecoderTest.java130
-rw-r--r--java/common/src/test/java/org/apache/qpid/codec/MockAMQVersionAwareProtocolSession.java84
-rw-r--r--java/common/src/test/java/org/apache/qpid/framing/abstraction/MessagePublishInfoImplTest.java99
-rw-r--r--java/common/src/test/java/org/apache/qpid/pool/PoolingFilterTest.java111
-rw-r--r--java/common/src/test/java/org/apache/qpid/thread/ThreadFactoryTest.java46
-rw-r--r--java/common/src/test/java/org/apache/qpid/transport/ConnectionTest.java391
-rw-r--r--java/common/src/test/java/org/apache/qpid/transport/GenTest.java44
-rw-r--r--java/common/src/test/java/org/apache/qpid/transport/TestNetworkDriver.java122
-rw-r--r--java/common/src/test/java/org/apache/qpid/transport/codec/BBEncoderTest.java47
-rw-r--r--java/common/src/test/java/org/apache/qpid/transport/network/mina/MINANetworkDriverTest.java491
-rw-r--r--java/common/src/test/java/org/apache/qpid/util/FileUtilsTest.java612
-rw-r--r--java/common/src/test/java/org/apache/qpid/util/SerialTest.java21
-rw-r--r--java/common/templates/model/ProtocolVersionListClass.vm25
-rw-r--r--java/common/templating.py18
149 files changed, 8281 insertions, 4434 deletions
diff --git a/java/common/Composite.tpl b/java/common/Composite.tpl
index 4aed9b0432..97b7d01f3c 100644
--- a/java/common/Composite.tpl
+++ b/java/common/Composite.tpl
@@ -1,4 +1,25 @@
-package $(pkg);
+package org.apache.qpid.transport;
+/*
+ *
+ * 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.util.ArrayList;
@@ -7,17 +28,15 @@ import java.util.List;
import java.util.Map;
import java.util.UUID;
-import org.apache.qpid.transport.Future;
-import org.apache.qpid.transport.Method;
-import org.apache.qpid.transport.RangeSet;
-import org.apache.qpid.transport.Struct;
-
import org.apache.qpid.transport.codec.Decoder;
import org.apache.qpid.transport.codec.Encodable;
import org.apache.qpid.transport.codec.Encoder;
import org.apache.qpid.transport.network.Frame;
+import org.apache.qpid.util.Strings;
+
+
${
from genutil import *
@@ -73,7 +92,7 @@ public final class $name extends $base {
return $pack;
}
- public final boolean hasPayloadSegment() {
+ public final boolean hasPayload() {
return $payload;
}
@@ -108,7 +127,12 @@ if fields:
${
for f in fields:
if f.option: continue
- out(" $(f.set)($(f.name));\n")
+ if f.ref_type != f.type:
+ out(" $(f.set)($(f.name));\n")
+ else:
+ out(" if($(f.name) != null) {\n")
+ out(" $(f.set)($(f.name));\n")
+ out(" }\n")
if segments:
out(" setHeader(header);\n")
@@ -126,6 +150,7 @@ if options or base == "Method":
if base == "Method":
out(""" case SYNC: this.setSync(true); break;
case BATCH: this.setBatch(true); break;
+ case UNRELIABLE: this.setUnreliable(true); break;
""")
out(""" case NONE: break;
default: throw new IllegalArgumentException("invalid option: " + _options[i]);
@@ -135,9 +160,13 @@ if options or base == "Method":
}
}
- public final <C> void dispatch(C context, MethodDelegate<C> delegate) {
+${
+
+if base == "Method":
+ out(""" public <C> void dispatch(C context, MethodDelegate<C> delegate) {
delegate.$(dromedary(name))(context, this);
- }
+ }""")
+}
${
for f in fields:
@@ -175,7 +204,13 @@ if not f.empty:
}
${
if pack > 0:
- out(" packing_flags |= $(f.flag_mask(pack));")
+ if f.empty:
+ out(" if (value)\\n")
+ out(" packing_flags |= $(f.flag_mask(pack));\\n")
+ out(" else\\n")
+ out(" packing_flags &= ~$(f.flag_mask(pack));")
+ else:
+ out(" packing_flags |= $(f.flag_mask(pack));")
}
this.dirty = true;
return this;
@@ -222,6 +257,26 @@ if segments:
setBody(body);
return this;
}
+
+ public final byte[] getBodyBytes() {
+ ByteBuffer buf = getBody();
+ byte[] bytes = new byte[buf.remaining()];
+ buf.get(bytes);
+ return bytes;
+ }
+
+ public final void setBody(byte[] body)
+ {
+ setBody(ByteBuffer.wrap(body));
+ }
+
+ public final String getBodyString() {
+ return Strings.fromUTF8(getBodyBytes());
+ }
+
+ public final void setBody(String body) {
+ setBody(Strings.toUTF8(body));
+ }
""")
}
diff --git a/java/common/Constant.tpl b/java/common/Constant.tpl
index 9f64cc657c..da4233c847 100644
--- a/java/common/Constant.tpl
+++ b/java/common/Constant.tpl
@@ -1,4 +1,25 @@
-package $(pkg);
+package org.apache.qpid.transport;
+/*
+ *
+ * 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.
+ *
+ */
+
${from genutil import *}
diff --git a/java/common/Enum.tpl b/java/common/Enum.tpl
index 7ff451997a..0835d34a20 100644
--- a/java/common/Enum.tpl
+++ b/java/common/Enum.tpl
@@ -1,4 +1,25 @@
-package $(pkg);
+package org.apache.qpid.transport;
+/*
+ *
+ * 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 enum $name {
${
diff --git a/java/common/Invoker.tpl b/java/common/Invoker.tpl
index 43aaced780..2eed43ad28 100644
--- a/java/common/Invoker.tpl
+++ b/java/common/Invoker.tpl
@@ -1,23 +1,37 @@
-package $(pkg);
+package org.apache.qpid.transport;
+/*
+ *
+ * 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.util.List;
import java.util.Map;
import java.util.UUID;
-import org.apache.qpid.transport.Future;
-import org.apache.qpid.transport.Method;
-import org.apache.qpid.transport.RangeSet;
-import org.apache.qpid.transport.Struct;
-
-public abstract class Invoker {
-
- protected abstract void invoke(Method method);
- protected abstract <T> Future<T> invoke(Method method, Class<T> resultClass);
-
+public abstract class $(invoker) {
${
from genutil import *
+results = False
+
for c in composites:
name = cname(c)
fields = get_fields(c)
@@ -25,6 +39,7 @@ for c in composites:
args = get_arguments(c, fields)
result = c["result"]
if result:
+ results = True
if not result["@type"]:
rname = cname(result["struct"])
else:
@@ -37,11 +52,22 @@ for c in composites:
jreturn = ""
jclass = ""
+ if c.name == "command":
+ access = "public "
+ else:
+ access = ""
+
out("""
- public final $jresult $(dromedary(name))($(", ".join(params))) {
+ $(access)final $jresult $(dromedary(name))($(", ".join(params))) {
$(jreturn)invoke(new $name($(", ".join(args)))$jclass);
}
""")
}
-
+ protected abstract void invoke(Method method);
+${
+if results:
+ out("""
+ protected abstract <T> Future<T> invoke(Method method, Class<T> resultClass);
+""")
+}
}
diff --git a/java/common/MethodDelegate.tpl b/java/common/MethodDelegate.tpl
index d2491dcf3a..27e20a7ef2 100644
--- a/java/common/MethodDelegate.tpl
+++ b/java/common/MethodDelegate.tpl
@@ -1,12 +1,37 @@
-package $(pkg);
+package org.apache.qpid.transport;
+/*
+ *
+ * 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 MethodDelegate<C> {
+ public abstract void handle(C context, Method method);
${
from genutil import *
for c in composites:
name = cname(c)
- out(" public void $(dromedary(name))(C context, $name struct) {}\n")
+ out("""
+ public void $(dromedary(name))(C context, $name method) {
+ handle(context, method);
+ }""")
}
}
diff --git a/java/common/Option.tpl b/java/common/Option.tpl
index c1e8dcbe22..c22b35b999 100644
--- a/java/common/Option.tpl
+++ b/java/common/Option.tpl
@@ -1,24 +1,42 @@
-package $(pkg);
+package org.apache.qpid.transport;
+/*
+ *
+ * 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 enum Option {
${
from genutil import *
-names = ["NONE", "SYNC", "BATCH"]
+options = {}
+
for c in composites:
for f in c.query["field"]:
t = resolve_type(f)
if t["@name"] == "bit":
- names.append(scream(f["@name"]))
-
-options = {}
-
-for option in names:
- if not options.has_key(option):
- if options:
- out(",\n ")
- options[option] = None
- out("$option")
-}
+ option = scream(f["@name"])
+ if not options.has_key(option):
+ options[option] = None
+ out(" $option,\n")}
+ BATCH,
+ UNRELIABLE,
+ NONE
}
diff --git a/java/common/StructFactory.tpl b/java/common/StructFactory.tpl
index 533005d561..09c669f74e 100644
--- a/java/common/StructFactory.tpl
+++ b/java/common/StructFactory.tpl
@@ -1,6 +1,25 @@
-package $(pkg);
+package org.apache.qpid.transport;
+/*
+ *
+ * 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.qpid.transport.Struct;
class StructFactory {
diff --git a/java/common/Type.tpl b/java/common/Type.tpl
index 818a53ffcf..7f9cfee268 100644
--- a/java/common/Type.tpl
+++ b/java/common/Type.tpl
@@ -1,4 +1,25 @@
-package $(pkg);
+package org.apache.qpid.transport;
+/*
+ *
+ * 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.
+ *
+ */
+
${from genutil import *}
diff --git a/java/common/bin/qpid-run b/java/common/bin/qpid-run
index 1de0048f48..63bb648fd8 100755
--- a/java/common/bin/qpid-run
+++ b/java/common/bin/qpid-run
@@ -56,6 +56,12 @@ if [ -z $AMQJ_LOGGING_LEVEL ]; then
export AMQJ_LOGGING_LEVEL=info
fi
+#Set to help us get round the manifold problems of ps/pgrep on various
+#platforms which gather up to prevent qpid_stop from working .....
+if [ -z "$QPID_PNAME" ]; then
+ export QPID_PNAME=" -DPNAME=QPBRKR"
+fi
+
if [ -z "$QPID_HOME" ]; then
export QPID_HOME=$(dirname $(dirname $(readlink -f $0)))
export PATH=${PATH}:${QPID_HOME}/bin
@@ -105,6 +111,7 @@ if [ -n "$QPID_LOG_SUFFIX" ]; then
fi
log $INFO System Properties set to $SYSTEM_PROPS
+log $INFO QPID_OPTS set to $QPID_OPTS
program=$(basename $0)
sourced=${BASH_SOURCE[0]}
@@ -253,6 +260,6 @@ if $cygwin; then
JAVA=$(cygpath -u $JAVA)
fi
-COMMAND=($JAVA $JAVA_VM $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/build.xml b/java/common/build.xml
index 13c500b24e..44cc19aa07 100644
--- a/java/common/build.xml
+++ b/java/common/build.xml
@@ -20,18 +20,18 @@
-->
<project name="AMQ Common" default="build">
+ <property name="module.genpom" value="true"/>
+
<import file="../module.xml"/>
<property name="gentools.home" location="${project.root}/../gentools" />
<property name="generated.package" value="org/apache/qpid/framing" />
<property name="generated.dir" location="${module.precompiled}/${generated.package}" />
<property name="xml.spec.dir" location="${project.root}/../specs" />
- <property name="xml.spec.deps" value="amqp.0-8.xml amqp.0-9.xml" />
- <property name="xml.spec.list" value="${xml.spec.dir}/amqp.0-8.xml ${xml.spec.dir}/amqp.0-9.xml" />
- <property name="mllib.dir" value="${project.root}/../python" />
+ <property name="xml.spec.deps" value="amqp.0-8.xml amqp.0-9.xml amqp0-9-1.stripped.xml" />
+ <property name="xml.spec.list" value="${xml.spec.dir}/amqp.0-8.xml ${xml.spec.dir}/amqp.0-9.xml ${xml.spec.dir}/amqp0-9-1.stripped.xml" />
<property name="gentools.timestamp" location="${generated.dir}/gentools.timestamp" />
- <property name="jython.timestamp" location="${module.precompiled}/jython.timestamp" />
- <property name="jython_1_0.timestamp" location="${module.precompiled}/jython_1_0.timestamp" />
+ <property name="jython.timestamp" location="${generated.dir}/jython.timestamp" />
<target name="check_jython_deps">
<uptodate property="jython.notRequired" targetfile="${jython.timestamp}">
@@ -40,43 +40,17 @@
</target>
<target name="jython" depends="check_jython_deps" unless="jython.notRequired">
- <java classname="org.python.util.jython" fork="true" failonerror="true">
- <arg value="-Dpython.cachedir.skip=true"/>
- <arg value="-Dpython.path=${basedir}/jython-lib.jar/Lib${path.separator}${mllib.dir}"/>
- <arg value="${basedir}/codegen"/>
- <arg value="${module.precompiled}"/>
- <arg value="${xml.spec.dir}/amqp.0-10-qpid-errata.xml"/>
- <arg value="${basedir}"/>
- <arg value="org/apache/qpid/transport"/>
- <classpath>
- <pathelement location="jython-2.2-rc2.jar"/>
- </classpath>
- </java>
+ <jython path="${mllib.dir}">
+ <args>
+ <arg value="${basedir}/codegen"/>
+ <arg value="${module.precompiled}"/>
+ <arg value="${xml.spec.dir}/amqp.0-10-qpid-errata.xml"/>
+ <arg value="${basedir}"/>
+ </args>
+ </jython>
<touch file="${jython.timestamp}" />
</target>
- <target name="check_jython_deps_1_0">
- <uptodate property="jython.notRequired_1_0" targetfile="${jython_1_0.timestamp}">
- <srcfiles dir="${xml.spec.dir}" includes="amqp.1-0-draft.xml" />
- </uptodate>
- </target>
-
- <target name="jython_1_0" depends="check_jython_deps_1_0" unless="jython.notRequired_1_0">
- <java classname="org.python.util.jython" fork="true" failonerror="true">
- <arg value="-Dpython.cachedir.skip=true"/>
- <arg value="-Dpython.path=${basedir}/jython-lib.jar/Lib${path.separator}${mllib.dir}"/>
- <arg value="${basedir}/codegen"/>
- <arg value="${module.precompiled}"/>
- <arg value="${xml.spec.dir}/amqp.1-0-draft.xml"/>
- <arg value="${basedir}"/>
- <arg value="org/apache/qpid/transport/v1_0"/>
- <classpath>
- <pathelement location="jython-2.2-rc2.jar"/>
- </classpath>
- </java>
- <touch file="${jython_1_0.timestamp}" />
- </target>
-
<target name="compile_gentools">
<ant dir="${gentools.home}" />
</target>
@@ -103,30 +77,7 @@
<touch file="${gentools.timestamp}" />
</target>
- <property name="version.file" location="${module.classes}/qpidversion.properties"/>
- <property file="${version.file}" prefix="old."/>
-
- <target name="check-version">
- <exec executable="svnversion" spawn="false" failifexecutionfails="false"
- dir="${project.root}" outputproperty="qpid.svnversion">
- <arg line="."/>
- </exec>
- <condition property="version.stale">
- <not>
- <equals arg1="${qpid.svnversion}" arg2="${old.qpid.svnversion}"/>
- </not>
- </condition>
- </target>
-
- <target name="version" depends="check-version" if="version.stale">
- <!-- Write the version.properties out. -->
- <echo file="${version.file}" append="true">
- qpid.svnversion=${qpid.svnversion}
- qpid.name=${project.name}
- qpid.version=${project.version}
- </echo>
- </target>
-
- <target name="precompile" depends="gentools,jython,jython_1_0,version"/>
+ <target name="precompile" depends="gentools,jython,create-version"/>
+ <target name="bundle" depends="bundle-tasks"/>
</project>
diff --git a/java/common/codegen b/java/common/codegen
index 07c5e5c6fb..6a1effc07b 100755
--- a/java/common/codegen
+++ b/java/common/codegen
@@ -1,5 +1,24 @@
#!/usr/bin/env python
+#
+# 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 os, sys, mllib
from templating import Parser
from genutil import *
@@ -7,9 +26,7 @@ from genutil import *
out_dir = sys.argv[1]
spec_file = sys.argv[2]
tpl_dir = sys.argv[3]
-pkg_rel = sys.argv[4]
-pkg_dir = os.path.join(out_dir, pkg_rel)
-pkg = pkg_rel.replace("/", ".")
+pkg_dir = os.path.join(out_dir, "org/apache/qpid/transport")
if not os.path.exists(pkg_dir):
os.makedirs(pkg_dir)
@@ -35,8 +52,8 @@ def execute(output, template, **kwargs):
f.write(p.output)
f.close()
-execute("Type.java", "Type.tpl", spec = spec, pkg = pkg)
-execute("Constant.java", "Constant.tpl", spec = spec, pkg = pkg)
+execute("Type.java", "Type.tpl", spec = spec)
+execute("Constant.java", "Constant.tpl", spec = spec)
structs = spec.query["amqp/struct"] + \
spec.query["amqp/class/struct", excludes] + \
@@ -45,15 +62,21 @@ controls = spec.query["amqp/class/control", excludes]
commands = spec.query["amqp/class/command", excludes]
composites = structs + controls + commands
+actions = controls + commands
+connection = [c for c in actions if c.parent["@name"] == "connection"]
+session = [c for c in actions if c.parent["@name"] != "connection"]
for c in composites:
name = cname(c)
- execute("%s.java" % name, "Composite.tpl", type = c, name = name, pkg = pkg)
+ execute("%s.java" % name, "Composite.tpl", type = c, name = name)
-execute("MethodDelegate.java", "MethodDelegate.tpl", composites = composites, pkg = pkg)
-execute("Option.java", "Option.tpl", composites = composites, pkg = pkg)
-execute("Invoker.java", "Invoker.tpl", composites = controls + commands, pkg = pkg)
-execute("StructFactory.java", "StructFactory.tpl", composites = composites, pkg = pkg)
+execute("MethodDelegate.java", "MethodDelegate.tpl", composites = actions)
+execute("Option.java", "Option.tpl", composites = composites)
+execute("ConnectionInvoker.java", "Invoker.tpl", invoker = "ConnectionInvoker",
+ composites = connection)
+execute("SessionInvoker.java", "Invoker.tpl", invoker = "SessionInvoker",
+ composites = session)
+execute("StructFactory.java", "StructFactory.tpl", composites = composites)
def is_enum(nd):
return nd["enum"] is not None
@@ -63,4 +86,4 @@ enums = spec.query["amqp/domain", is_enum] + \
for e in enums:
name = cname(e)
- execute("%s.java" % name, "Enum.tpl", name = name, type = e, pkg = pkg)
+ execute("%s.java" % name, "Enum.tpl", name = name, type = e)
diff --git a/java/common/genutil.py b/java/common/genutil.py
index f8f234548c..57a461ed40 100644
--- a/java/common/genutil.py
+++ b/java/common/genutil.py
@@ -1,3 +1,21 @@
+#
+# 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.
+#
def camel(offset, *args):
parts = []
@@ -180,6 +198,7 @@ class Field:
self.read = "dec.read%s()" % self.coder
self.write = "enc.write%s(check(struct).%s)" % (self.coder, self.name)
self.type = jtype(self.type_node)
+ self.ref_type = jref(self.type)
self.default = DEFAULTS.get(self.type, "null")
self.has = camel(1, "has", self.name)
self.get = camel(1, "get", self.name)
diff --git a/java/common/jython-2.2-rc2.jar b/java/common/jython-2.2-rc2.jar
deleted file mode 100644
index e25e2cb945..0000000000
--- a/java/common/jython-2.2-rc2.jar
+++ /dev/null
Binary files differ
diff --git a/java/common/jython-lib.jar b/java/common/jython-lib.jar
deleted file mode 100644
index bb3ba82db5..0000000000
--- a/java/common/jython-lib.jar
+++ /dev/null
Binary files differ
diff --git a/java/common/pom.xml b/java/common/pom.xml
deleted file mode 100644
index 894ca26710..0000000000
--- a/java/common/pom.xml
+++ /dev/null
@@ -1,187 +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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid-common</artifactId>
- <packaging>jar</packaging>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <name>Qpid Common Utilities</name>
- <url>http://cwiki.apache.org/confluence/display/qpid</url>
-
- <parent>
- <groupId>org.apache.qpid</groupId>
- <artifactId>qpid</artifactId>
- <version>1.0-incubating-M3-SNAPSHOT</version>
- <relativePath>../pom.xml</relativePath>
- </parent>
-
- <properties>
- <topDirectoryLocation>..</topDirectoryLocation>
- <gentools.home>${topDirectoryLocation}/../gentools</gentools.home>
- <generated.path>${project.build.directory}/generated-sources/gentools</generated.path>
- <generated.package>org/apache/qpid/framing</generated.package>
- <generated.dir>${generated.path}/${generated.package}</generated.dir>
- <generated.timestamp>${generated.dir}/timestamp</generated.timestamp>
- <specs.dir>${basedir}/../../specs</specs.dir>
- <mllib.dir>${basedir}/../../python</mllib.dir>
- </properties>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-antrun-plugin</artifactId>
- <executions>
- <execution>
- <id>protocol-version</id>
- <phase>generate-sources</phase>
- <configuration>
- <tasks>
- <echo>"${generated.path}"</echo>
- <ant antfile="protocol-version.xml" />
-<!-- <exec executable="python">
- <arg line="generate"/>
- <arg line="${generated.path}"/>
- <arg line="org.apache.qpid"/>
- <arg line="${specs.dir}/amqp-transitional.0-10.xml"/>
- </exec> -->
- </tasks>
- <sourceRoot>${generated.path}</sourceRoot>
- </configuration>
- <goals>
- <goal>run</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
-
- <plugin>
- <groupId>org.apache.qpid</groupId>
- <artifactId>jython-plugin</artifactId>
- <executions>
- <execution>
- <id>jython</id>
- <phase>generate-sources</phase>
- <configuration>
- <params>
- <param>-Dpython.cachedir.skip=true</param>
- <param>-Dpython.path=${basedir}/jython-lib.jar/Lib${path.separator}${mllib.dir}</param>
- <param>${basedir}/codegen</param>
- <param>${generated.path}</param>
- <param>${specs.dir}/amqp.0-10-qpid-errata.xml</param>
- <param>${basedir}</param>
- </params>
- <sources>
- <source>${specs.dir}/amqp.0-10-qpid-errata.xml</source>
- <source>${basedir}/codegen</source>
- </sources>
- <timestamp>${generated.path}/generated.timestamp</timestamp>
- </configuration>
- <goals>
- <goal>jython</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
-
-
-
- <!-- Backports the module to Java 1.4. This is done during the packaging phase as a transformation of the Jar. -->
- <plugin>
- <groupId>org.codehaus.mojo</groupId>
- <artifactId>retrotranslator-maven-plugin</artifactId>
- <executions>
- <execution>
- <id>retro-common</id>
- <goals>
- <goal>translate-project</goal>
- </goals>
- <configuration>
- <destjar>${project.build.directory}/${project.build.finalName}-java14.jar</destjar>
- <verify>${retrotranslator.verify}</verify>
- <verifyClasspath>
- <element>${retrotranslator.1.4-rt-path}</element>
- <element>${retrotranslator.1.4-jce-path}</element>
- <element>${retrotranslator.1.4-jsse-path}</element>
- <element>${retrotranslator.1.4-sasl-path}</element>
- </verifyClasspath>
- <failonwarning>false</failonwarning>
- <classifier>java14</classifier>
- <attach>true</attach>
- </configuration>
- </execution>
-
- </executions>
- </plugin>
-
- </plugins>
- </build>
-
- <dependencies>
-
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- <version>1.4.0</version>
- </dependency>
-
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-log4j12</artifactId>
- <version>1.4.0</version>
- <scope>test</scope>
- </dependency>
-<!--
- <dependency>
- <groupId>org.apache.mina</groupId>
- <artifactId>mina-java5</artifactId>
- </dependency>
--->
- <dependency>
- <groupId>org.apache.mina</groupId>
- <artifactId>mina-filter-ssl</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.apache.mina</groupId>
- <artifactId>mina-core</artifactId>
- </dependency>
-
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <scope>test</scope>
- </dependency>
-
- <!-- This needs to be included at compile time, for the retrotranslator verification to find it. -->
- <dependency>
- <groupId>net.sf.retrotranslator</groupId>
- <artifactId>retrotranslator-runtime</artifactId>
- <scope>provided</scope>
- </dependency>
- <!--- This is used by filter -->
- <dependency>
- <groupId>org.apache.geronimo.specs</groupId>
- <artifactId>geronimo-jms_1.1_spec</artifactId>
- </dependency>
- </dependencies>
-</project>
diff --git a/java/common/protocol-version.xml b/java/common/protocol-version.xml
index ee9db6049b..5435a0a582 100644
--- a/java/common/protocol-version.xml
+++ b/java/common/protocol-version.xml
@@ -27,8 +27,8 @@
<property name="generated.dir" location="${generated.path}/${generated.package}" />
<property name="generated.timestamp" location="${generated.dir}/timestamp" />
<property name="xml.spec.dir" location="${topDirectoryLocation}/../specs" />
- <property name="xml.spec.deps" value="amqp.0-8.xml amqp.0-9.xml" />
- <property name="xml.spec.list" value="${xml.spec.dir}/amqp.0-8.xml ${xml.spec.dir}/amqp.0-9.xml" />
+ <property name="xml.spec.deps" value="amqp.0-8.xml amqp.0-9.xml amqp0-9-1.stripped.xml" />
+ <property name="xml.spec.list" value="${xml.spec.dir}/amqp.0-8.xml ${xml.spec.dir}/amqp.0-9.xml ${xml.spec.dir}/amqp0-9-1.stripped.xml" />
<property name="template.dir" value="${topDirectoryLocation}/common/templates" />
diff --git a/java/common/src/main/java/common.bnd b/java/common/src/main/java/common.bnd
new file mode 100755
index 0000000000..120a2401d3
--- /dev/null
+++ b/java/common/src/main/java/common.bnd
@@ -0,0 +1,6 @@
+ver: 0.6.0
+
+Bundle-SymbolicName: qpid-common
+Bundle-Version: ${ver}
+Export-Package: *;version=${ver}
+Bundle-RequiredExecutionEnvironment: J2SE-1.5
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 afd415b1eb..8ef6facef1 100644
--- a/java/common/src/main/java/org/apache/qpid/AMQConnectionException.java
+++ b/java/common/src/main/java/org/apache/qpid/AMQConnectionException.java
@@ -60,7 +60,7 @@ public class AMQConnectionException extends AMQException
public AMQFrame getCloseFrame(int channel)
{
MethodRegistry reg = MethodRegistry.getMethodRegistry(new ProtocolVersion(major,minor));
- return new AMQFrame(channel,
+ return new AMQFrame(0,
reg.createConnectionCloseBody(getErrorCode().getCode(),
new AMQShortString(getMessage()),
_classId,
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 eda532b64e..be335c5dba 100644
--- a/java/common/src/main/java/org/apache/qpid/AMQException.java
+++ b/java/common/src/main/java/org/apache/qpid/AMQException.java
@@ -90,4 +90,33 @@ public class AMQException extends Exception
{
return true;
}
+
+ /**
+ * Rethrown this exception as a new exception.
+ *
+ * Attempt to create a new exception of the same class if they hav the default constructor of:
+ * {AMQConstant.class, String.class, Throwable.class}
+ *
+ * Individual subclasses may override as requried to create a new instance.
+ *
+ */
+ public AMQException cloneForCurrentThread()
+ {
+ Class amqeClass = this.getClass();
+ Class<?>[] paramClasses = {AMQConstant.class, String.class, Throwable.class};
+ Object[] params = {getErrorCode(), getMessage(), this};
+
+ AMQException newAMQE;
+
+ try
+ {
+ newAMQE = (AMQException) amqeClass.getConstructor(paramClasses).newInstance(params);
+ }
+ catch (Exception creationException)
+ {
+ newAMQE = new AMQException(getErrorCode(), getMessage(), this);
+ }
+
+ return newAMQE;
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/BrokerDetails.java b/java/common/src/main/java/org/apache/qpid/BrokerDetails.java
deleted file mode 100644
index 63f67a7857..0000000000
--- a/java/common/src/main/java/org/apache/qpid/BrokerDetails.java
+++ /dev/null
@@ -1,138 +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;
-
-import java.util.Map;
-
-/**
- * This interface represents a broker and provides the basic information
- * required for opening a connection with a broker.
- */
-public interface BrokerDetails
-{
- /**
- * Those are the supported protocols
- */
- public static final String PROTOCOL_TCP = "tcp";
- public static final String PROTOCOL_TLS = "tls";
-
- public static final String VIRTUAL_HOST = "virtualhost";
- public static final String CLIENT_ID = "client_id";
- public static final String USERNAME = "username";
- public static final String PASSWORD = "password";
-
- /**
- * Get the broker host name.
- *
- * @return The broker host name.
- */
- public String getHost();
-
- /**
- * Get the broker port number.
- *
- * @return The broker port number.
- */
- public int getPort();
-
- /**
- * Get the virtual host to connect to.
- *
- * @return The virtual host of this broker.
- */
- public String getVirtualHost();
-
- /**
- * Get the user name.
- *
- * @return The user name
- */
- public String getUserName();
-
- /**
- * Get the user password
- *
- * @return The user password
- */
- public String getPassword();
-
- /**
- * Get the protocol used to connect to hise broker.
- *
- * @return the protocol used to connect to the broker.
- */
- public String getProtocol();
-
- /**
- * Set the broker host name.
- *
- * @param host The broker host name.
- */
- public void setHost(String host);
-
- /**
- * Set the broker port number.
- *
- * @param port The broker port number.
- */
- public void setPort(int port);
-
- /**
- * Set the virtual host to connect to.
- *
- * @param virtualHost The virtual host of this broker.
- */
- public void setVirtualHost(String virtualHost);
-
- /**
- * Set the user name.
- *
- * @param userName The user name
- */
- public void setUserName(String userName);
-
- /**
- * Set the user password
- *
- * @param password The user password
- */
- public void setPassword(String password);
-
- /**
- * Set the protocol used to connect to hise broker.
- *
- * @param protocol the protocol used to connect to the broker.
- */
- public void setProtocol(String protocol);
-
- /**
- * Ex: keystore path
- *
- * @return the Properties associated with this connection.
- */
- public Map<String,String> getProperties();
-
- /**
- * Sets the properties associated with this connection
- *
- * @param props the new p[roperties.
- */
- public void setProperties(Map<String,String> props);
-
- public void setProperty(String key,String value);
-}
diff --git a/java/common/src/main/java/org/apache/qpid/BrokerDetailsImpl.java b/java/common/src/main/java/org/apache/qpid/BrokerDetailsImpl.java
deleted file mode 100644
index 201d43e21f..0000000000
--- a/java/common/src/main/java/org/apache/qpid/BrokerDetailsImpl.java
+++ /dev/null
@@ -1,264 +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;
-
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Implements the interface BrokerDetails
- */
-public class BrokerDetailsImpl implements BrokerDetails
-{
- //--- Those are the default values
- private final String DEFAULT_USERNAME = "guest";
- private final String DEFAULT_PASSWORD = "guest";
- private final String DEFAULT_VIRTUALHOST = "";
-
- //---- The brker details
- private String _host;
- private int _port = 0;
- private String _virtualHost;
- private String _userName = DEFAULT_USERNAME;
- private String _password = DEFAULT_PASSWORD;
- private String _protocol;
- private Map<String, String> _props = new HashMap<String, String>();
- ;
-
- //--- Constructors
-
- public BrokerDetailsImpl()
- {
- }
-
- /**
- * Create a new broker details given all the reuqired information
- *
- * @param protocol The protocol used for this broker connection
- * @param host The host name.
- * @param port The port number.
- * @param virtualHost The virtual host.
- * @param userName The user name.
- * @param password The user password.
- */
- public BrokerDetailsImpl(String protocol, String host, int port, String virtualHost, String userName,
- String password, Map<String, String> props)
- {
- _protocol = protocol;
- _host = host;
- _port = port;
- _virtualHost = virtualHost;
- _userName = userName;
- _password = password;
- _props = props;
- }
-
- /**
- * Create a new broker details given the host name and the procol type,
- * default values are used for the other details.
- *
- * @param protocol The protocol used for this broker connection
- * @param host The host name.
- */
- public BrokerDetailsImpl(String protocol, String host)
- {
- _protocol = protocol;
- _host = host;
- _virtualHost = DEFAULT_VIRTUALHOST;
- _userName = DEFAULT_USERNAME;
- _password = DEFAULT_PASSWORD;
- }
-
- //--- API BrokerDetails
- /**
- * Get the user password
- *
- * @return The user password
- */
- public String getPassword()
- {
- return _password;
- }
-
- /**
- * Get the broker host name.
- *
- * @return The broker host name.
- */
- public String getHost()
- {
- return _host;
- }
-
- /**
- * Get the broker port number.
- *
- * @return The broker port number.
- */
- public int getPort()
- {
- if (_port == 0)
- {
- if (getProtocol().equals(BrokerDetails.PROTOCOL_TCP))
- {
- _port = 5672;
- }
- else if (getProtocol().equals(BrokerDetails.PROTOCOL_TLS))
- {
- _port = 5555;
- }
- }
- return _port;
- }
-
- /**
- * Get the virtual host to connect to.
- *
- * @return The virtual host of this broker.
- */
- public String getVirtualHost()
- {
- return _virtualHost;
- }
-
- /**
- * Get the user name.
- *
- * @return The user name
- */
- public String getUserName()
- {
- return _userName;
- }
-
- /**
- * Get the protocol used to connect to hise broker.
- *
- * @return the protocol used to connect to the broker.
- */
- public String getProtocol()
- {
- return _protocol;
- }
-
- /**
- * Set the broker host name.
- *
- * @param host The broker host name.
- */
- public void setHost(String host)
- {
- _host = host;
- }
-
- /**
- * Set the broker port number.
- *
- * @param port The broker port number.
- */
- public void setPort(int port)
- {
- _port = port;
- }
-
- /**
- * Set the virtual host to connect to.
- *
- * @param virtualHost The virtual host of this broker.
- */
- public void setVirtualHost(String virtualHost)
- {
- _virtualHost = virtualHost;
- }
-
- /**
- * Set the user name.
- *
- * @param userName The user name
- */
- public void setUserName(String userName)
- {
- _userName = userName;
- }
-
- /**
- * Set the user password
- *
- * @param password The user password
- */
- public void setPassword(String password)
- {
- _password = password;
- }
-
- /**
- * Set the protocol used to connect to hise broker.
- *
- * @param protocol the protocol used to connect to the broker.
- */
- public void setProtocol(String protocol)
- {
- _protocol = protocol;
- }
-
- /**
- * Ex: keystore path
- *
- * @return the Properties associated with this connection.
- */
- public Map<String, String> getProperties()
- {
- return _props;
- }
-
- /**
- * Sets the properties associated with this connection
- *
- * @param props
- */
- public void setProperties(Map<String, String> props)
- {
- _props = props;
- }
-
- public void setProperty(String key, String value)
- {
- _props.put(key, value);
- }
-
- public String toString()
- {
- StringBuilder b = new StringBuilder();
- b.append("[username=" + _userName);
- b.append(",password=" + _password);
- b.append(",transport=" + _protocol);
- b.append(",host=" + _host);
- b.append(",port=" + getPort() + "]");
- b.append(" - Properties[");
- if (_props != null)
- {
- for (String k : _props.keySet())
- {
- b.append(k + "=" + _props.get(k) + ",");
- }
- }
- b.append("]");
-
- return b.toString();
- }
-}
diff --git a/java/common/src/main/java/org/apache/qpid/ConsoleOutput.java b/java/common/src/main/java/org/apache/qpid/ConsoleOutput.java
index f17782ebf4..7d8a5b7b36 100644
--- a/java/common/src/main/java/org/apache/qpid/ConsoleOutput.java
+++ b/java/common/src/main/java/org/apache/qpid/ConsoleOutput.java
@@ -20,12 +20,12 @@
*/
package org.apache.qpid;
+import static org.apache.qpid.transport.util.Functions.str;
+
import java.nio.ByteBuffer;
import org.apache.qpid.transport.Sender;
-import static org.apache.qpid.transport.util.Functions.*;
-
/**
* ConsoleOutput
@@ -51,4 +51,12 @@ public class ConsoleOutput implements Sender<ByteBuffer>
System.out.println("CLOSED");
}
+ public void setIdleTimeout(long l)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/ErrorCode.java b/java/common/src/main/java/org/apache/qpid/ErrorCode.java
index be1ad16dd5..0549869e71 100644
--- a/java/common/src/main/java/org/apache/qpid/ErrorCode.java
+++ b/java/common/src/main/java/org/apache/qpid/ErrorCode.java
@@ -1,4 +1,25 @@
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.
+ *
+ */
+
public enum ErrorCode
{
@@ -99,4 +120,4 @@ public enum ErrorCode
An invalid or illegal argument was passed to a method, and the operation could not proceed.
</doc>
</constant>
-*/ \ No newline at end of file
+*/
diff --git a/java/common/src/main/java/org/apache/qpid/QpidConfig.java b/java/common/src/main/java/org/apache/qpid/QpidConfig.java
index e8d42fdf83..9c8019f109 100644
--- a/java/common/src/main/java/org/apache/qpid/QpidConfig.java
+++ b/java/common/src/main/java/org/apache/qpid/QpidConfig.java
@@ -1,4 +1,25 @@
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.
+ *
+ */
+
/**
* API to configure the Security parameters of the client.
diff --git a/java/common/src/main/java/org/apache/qpid/SecurityHelper.java b/java/common/src/main/java/org/apache/qpid/SecurityHelper.java
deleted file mode 100644
index dda5a6506d..0000000000
--- a/java/common/src/main/java/org/apache/qpid/SecurityHelper.java
+++ /dev/null
@@ -1,71 +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;
-
-import java.io.UnsupportedEncodingException;
-import java.util.HashSet;
-import java.util.List;
-import java.util.StringTokenizer;
-
-import org.apache.qpid.security.AMQPCallbackHandler;
-import org.apache.qpid.security.CallbackHandlerRegistry;
-
-public class SecurityHelper
-{
- public static String chooseMechanism(List<Object> mechanisms) throws UnsupportedEncodingException
- {
- HashSet mechanismSet = new HashSet();
- for (Object m : mechanisms)
- {
- mechanismSet.add(m);
- }
-
- String preferredMechanisms = CallbackHandlerRegistry.getInstance().getMechanisms();
- StringTokenizer prefTokenizer = new StringTokenizer(preferredMechanisms, " ");
- while (prefTokenizer.hasMoreTokens())
- {
- String mech = prefTokenizer.nextToken();
- if (mechanismSet.contains(mech))
- {
- return mech;
- }
- }
- return null;
- }
-
- public static AMQPCallbackHandler createCallbackHandler(String mechanism, String username,String password)
- throws QpidException
- {
- Class mechanismClass = CallbackHandlerRegistry.getInstance().getCallbackHandlerClass(mechanism);
- try
- {
- Object instance = mechanismClass.newInstance();
- AMQPCallbackHandler cbh = (AMQPCallbackHandler) instance;
- cbh.initialise(username,password);
- return cbh;
- }
- catch (Exception e)
- {
- throw new QpidException("Unable to create callback handler: " + e,ErrorCode.UNDEFINED, e.getCause());
- }
- }
-
-}
diff --git a/java/common/src/main/java/org/apache/qpid/SerialException.java b/java/common/src/main/java/org/apache/qpid/SerialException.java
index 4fc8458e45..c59a6af779 100644
--- a/java/common/src/main/java/org/apache/qpid/SerialException.java
+++ b/java/common/src/main/java/org/apache/qpid/SerialException.java
@@ -1,4 +1,25 @@
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.
+ *
+ */
+
/**
* This exception is used by the serial class (imp RFC 1982)
diff --git a/java/common/src/main/java/org/apache/qpid/ToyBroker.java b/java/common/src/main/java/org/apache/qpid/ToyBroker.java
index 83d434b20a..db84b83adb 100644
--- a/java/common/src/main/java/org/apache/qpid/ToyBroker.java
+++ b/java/common/src/main/java/org/apache/qpid/ToyBroker.java
@@ -174,23 +174,14 @@ class ToyBroker extends SessionDelegate
public static final void main(String[] args) throws IOException
{
final ToyExchange exchange = new ToyExchange();
- ConnectionDelegate delegate = new ConnectionDelegate()
+ ConnectionDelegate delegate = new ServerDelegate()
{
public SessionDelegate getSessionDelegate()
{
return new ToyBroker(exchange);
}
- public void exception(Throwable t)
- {
- t.printStackTrace();
- }
- public void closed() {}
};
- //hack
- delegate.setUsername("guest");
- delegate.setPassword("guest");
-
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
index cb10859c9f..5b2db10613 100644
--- a/java/common/src/main/java/org/apache/qpid/ToyClient.java
+++ b/java/common/src/main/java/org/apache/qpid/ToyClient.java
@@ -33,48 +33,30 @@ import org.apache.qpid.transport.network.mina.MinaHandler;
* @author Rafael H. Schloming
*/
-class ToyClient extends SessionDelegate
+class ToyClient implements SessionListener
{
+ public void opened(Session ssn) {}
- @Override public void messageReject(Session ssn, MessageReject reject)
+ public void resumed(Session ssn) {}
+
+ public void exception(Session ssn, SessionException exc)
{
- for (Range range : reject.getTransfers())
- {
- for (long l = range.getLower(); l <= range.getUpper(); l++)
- {
- System.out.println("message rejected: " +
- ssn.getCommand((int) l));
- }
- }
+ exc.printStackTrace();
}
- @Override public void messageTransfer(Session ssn, MessageTransfer xfr)
+ 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 = MinaHandler.connect("0.0.0.0", 5672,
- new ClientDelegate()
- {
- public SessionDelegate getSessionDelegate()
- {
- return new ToyClient();
- }
- public void exception(Throwable t)
- {
- t.printStackTrace();
- }
- public void closed() {}
- });
- conn.send(new ProtocolHeader
- (1, 0, 10));
-
- Channel ch = conn.getChannel(0);
- Session ssn = new Session("my-session".getBytes());
- ssn.attach(ch);
- ssn.sessionAttach(ssn.getName());
+ 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();
diff --git a/java/common/src/main/java/org/apache/qpid/ToyExchange.java b/java/common/src/main/java/org/apache/qpid/ToyExchange.java
index c638679596..da6aed9629 100644
--- a/java/common/src/main/java/org/apache/qpid/ToyExchange.java
+++ b/java/common/src/main/java/org/apache/qpid/ToyExchange.java
@@ -1,4 +1,25 @@
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;
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 fa890d0ebb..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
@@ -23,6 +23,7 @@ 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;
/**
* AMQCodecFactory is a Mina codec factory. It supplies the encoders and decoders need to read and write the bytes to
@@ -50,9 +51,9 @@ public class AMQCodecFactory implements ProtocolCodecFactory
* @param expectProtocolInitiation <tt>true</tt> if the first frame received is going to be a protocol initiation
* frame, <tt>false</tt> if it is going to be a standard AMQ data block.
*/
- public AMQCodecFactory(boolean expectProtocolInitiation)
+ public AMQCodecFactory(boolean expectProtocolInitiation, AMQVersionAwareProtocolSession session)
{
- _frameDecoder = new AMQDecoder(expectProtocolInitiation);
+ _frameDecoder = new AMQDecoder(expectProtocolInitiation, session);
}
/**
@@ -70,7 +71,7 @@ public class AMQCodecFactory implements ProtocolCodecFactory
*
* @return The AMQP decoder.
*/
- public ProtocolDecoder getDecoder()
+ public AMQDecoder getDecoder()
{
return _frameDecoder;
}
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 7eef73f337..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,14 +20,21 @@
*/
package org.apache.qpid.codec;
+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;
+import org.apache.qpid.framing.AMQFrameDecodingException;
+import org.apache.qpid.framing.AMQMethodBodyFactory;
+import org.apache.qpid.framing.AMQProtocolVersionException;
import org.apache.qpid.framing.ProtocolInitiation;
+import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
/**
* AMQDecoder delegates the decoding of AMQP either to a data block decoder, or in the case of new connections, to a
@@ -62,14 +69,19 @@ public class AMQDecoder extends CumulativeProtocolDecoder
private boolean _expectProtocolInitiation;
private boolean firstDecode = true;
+ private AMQMethodBodyFactory _bodyFactory;
+
+ private ByteBuffer _remainingBuf;
+
/**
* Creates a new AMQP decoder.
*
* @param expectProtocolInitiation <tt>true</tt> if this decoder needs to handle protocol initiation.
*/
- public AMQDecoder(boolean expectProtocolInitiation)
+ public AMQDecoder(boolean expectProtocolInitiation, AMQVersionAwareProtocolSession session)
{
_expectProtocolInitiation = expectProtocolInitiation;
+ _bodyFactory = new AMQMethodBodyFactory(session);
}
/**
@@ -120,7 +132,7 @@ public class AMQDecoder extends CumulativeProtocolDecoder
protected boolean doDecodeDataBlock(IoSession session, ByteBuffer in, ProtocolDecoderOutput out) throws Exception
{
int pos = in.position();
- boolean enoughData = _dataBlockDecoder.decodable(session, in);
+ boolean enoughData = _dataBlockDecoder.decodable(in.buf());
in.position(pos);
if (!enoughData)
{
@@ -149,7 +161,7 @@ public class AMQDecoder extends CumulativeProtocolDecoder
*/
private boolean doDecodePI(IoSession session, ByteBuffer in, ProtocolDecoderOutput out) throws Exception
{
- boolean enoughData = _piDecoder.decodable(session, in);
+ boolean enoughData = _piDecoder.decodable(in.buf());
if (!enoughData)
{
// returning false means it will leave the contents in the buffer and
@@ -158,7 +170,8 @@ public class AMQDecoder extends CumulativeProtocolDecoder
}
else
{
- _piDecoder.decode(session, in, out);
+ ProtocolInitiation pi = new ProtocolInitiation(in.buf());
+ out.write(pi);
return true;
}
@@ -177,7 +190,7 @@ public class AMQDecoder extends CumulativeProtocolDecoder
}
- /**
+ /**
* 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>
@@ -268,4 +281,60 @@ public class AMQDecoder extends CumulativeProtocolDecoder
session.setAttribute( BUFFER, remainingBuf );
}
+ public ArrayList<AMQDataBlock> decodeBuffer(java.nio.ByteBuffer buf) throws AMQFrameDecodingException, AMQProtocolVersionException
+ {
+
+ // get prior remaining data from accumulator
+ ArrayList<AMQDataBlock> dataBlocks = new ArrayList<AMQDataBlock>();
+ ByteBuffer msg;
+ // if we have a session buffer, append data to that otherwise
+ // use the buffer read from the network directly
+ if( _remainingBuf != null )
+ {
+ _remainingBuf.put(buf);
+ _remainingBuf.flip();
+ msg = _remainingBuf;
+ }
+ else
+ {
+ msg = ByteBuffer.wrap(buf);
+ }
+
+ if (_expectProtocolInitiation
+ || (firstDecode
+ && (msg.remaining() > 0)
+ && (msg.get(msg.position()) == (byte)'A')))
+ {
+ if (_piDecoder.decodable(msg.buf()))
+ {
+ dataBlocks.add(new ProtocolInitiation(msg.buf()));
+ }
+ }
+ else
+ {
+ boolean enoughData = true;
+ while (enoughData)
+ {
+ int pos = msg.position();
+
+ enoughData = _dataBlockDecoder.decodable(msg);
+ msg.position(pos);
+ if (enoughData)
+ {
+ dataBlocks.add(_dataBlockDecoder.createAndPopulateFrame(_bodyFactory, msg));
+ }
+ else
+ {
+ _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/framing/AMQDataBlockDecoder.java b/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockDecoder.java
index 82ffc60802..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
@@ -47,7 +47,7 @@ public class AMQDataBlockDecoder
public AMQDataBlockDecoder()
{ }
- public boolean decodable(IoSession session, ByteBuffer in) throws AMQFrameDecodingException
+ public boolean decodable(java.nio.ByteBuffer in) throws AMQFrameDecodingException
{
final int remainingAfterAttributes = in.remaining() - (1 + 2 + 4 + 1);
// type, channel, body length and end byte
@@ -56,14 +56,15 @@ public class AMQDataBlockDecoder
return false;
}
- in.skip(1 + 2);
- final long bodySize = in.getUnsignedInt();
+ in.position(in.position() + 1 + 2);
+ // Get an unsigned int, lifted from MINA ByteBuffer getUnsignedInt()
+ final long bodySize = in.getInt() & 0xffffffffL;
return (remainingAfterAttributes >= bodySize);
}
- protected Object createAndPopulateFrame(IoSession session, ByteBuffer in)
+ public AMQFrame createAndPopulateFrame(AMQMethodBodyFactory methodBodyFactory, ByteBuffer in)
throws AMQFrameDecodingException, AMQProtocolVersionException
{
final byte type = in.get();
@@ -71,15 +72,7 @@ public class AMQDataBlockDecoder
BodyFactory bodyFactory;
if (type == AMQMethodBody.TYPE)
{
- bodyFactory = (BodyFactory) 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);
-
- }
-
+ bodyFactory = methodBodyFactory;
}
else
{
@@ -115,6 +108,24 @@ public class AMQDataBlockDecoder
public void decode(IoSession session, ByteBuffer in, ProtocolDecoderOutput out) throws Exception
{
- out.write(createAndPopulateFrame(session, in));
+ 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
index 05fd2bb480..374644b4f2 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockEncoder.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/AMQDataBlockEncoder.java
@@ -50,7 +50,7 @@ public final class AMQDataBlockEncoder implements MessageEncoder
{
_logger.debug("Encoded frame byte-buffer is '" + EncodingUtils.convertToHexString(buffer) + "'");
}
-
+
out.write(buffer);
}
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 ad7f36f790..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
@@ -93,4 +93,166 @@ public abstract class AMQMethodBodyImpl implements AMQMethodBody
session.methodFrameReceived(channelId, this);
}
+ public int getSize()
+ {
+ return 2 + 2 + getBodySize();
+ }
+
+ public void writePayload(ByteBuffer buffer)
+ {
+ EncodingUtils.writeUnsignedShort(buffer, getClazz());
+ EncodingUtils.writeUnsignedShort(buffer, getMethod());
+ writeMethodPayload(buffer);
+ }
+
+
+ protected byte readByte(ByteBuffer buffer)
+ {
+ return buffer.get();
+ }
+
+ protected AMQShortString readAMQShortString(ByteBuffer buffer)
+ {
+ return EncodingUtils.readAMQShortString(buffer);
+ }
+
+ protected int getSizeOf(AMQShortString string)
+ {
+ return EncodingUtils.encodedShortStringLength(string);
+ }
+
+ protected void writeByte(ByteBuffer buffer, byte b)
+ {
+ buffer.put(b);
+ }
+
+ protected void writeAMQShortString(ByteBuffer buffer, AMQShortString string)
+ {
+ EncodingUtils.writeShortStringBytes(buffer, string);
+ }
+
+ protected int readInt(ByteBuffer buffer)
+ {
+ return buffer.getInt();
+ }
+
+ protected void writeInt(ByteBuffer buffer, int i)
+ {
+ buffer.putInt(i);
+ }
+
+ protected FieldTable readFieldTable(ByteBuffer buffer) throws AMQFrameDecodingException
+ {
+ return EncodingUtils.readFieldTable(buffer);
+ }
+
+ protected int getSizeOf(FieldTable table)
+ {
+ return EncodingUtils.encodedFieldTableLength(table); //To change body of created methods use File | Settings | File Templates.
+ }
+
+ protected void writeFieldTable(ByteBuffer buffer, FieldTable table)
+ {
+ EncodingUtils.writeFieldTableBytes(buffer, table);
+ }
+
+ protected long readLong(ByteBuffer buffer)
+ {
+ return buffer.getLong();
+ }
+
+ protected void writeLong(ByteBuffer buffer, long l)
+ {
+ buffer.putLong(l);
+ }
+
+ protected int getSizeOf(byte[] response)
+ {
+ return (response == null) ? 4 : response.length + 4;
+ }
+
+ protected void writeBytes(ByteBuffer buffer, byte[] data)
+ {
+ EncodingUtils.writeBytes(buffer,data);
+ }
+
+ protected byte[] readBytes(ByteBuffer buffer)
+ {
+ return EncodingUtils.readBytes(buffer);
+ }
+
+ protected short readShort(ByteBuffer buffer)
+ {
+ return EncodingUtils.readShort(buffer);
+ }
+
+ protected void writeShort(ByteBuffer buffer, short s)
+ {
+ EncodingUtils.writeShort(buffer, s);
+ }
+
+ protected Content readContent(ByteBuffer buffer)
+ {
+ return null; //To change body of created methods use File | Settings | File Templates.
+ }
+
+ protected int getSizeOf(Content body)
+ {
+ return 0; //To change body of created methods use File | Settings | File Templates.
+ }
+
+ protected void writeContent(ByteBuffer buffer, Content body)
+ {
+ //To change body of created methods use File | Settings | File Templates.
+ }
+
+ protected byte readBitfield(ByteBuffer buffer)
+ {
+ return readByte(buffer); //To change body of created methods use File | Settings | File Templates.
+ }
+
+ protected int readUnsignedShort(ByteBuffer buffer)
+ {
+ return buffer.getUnsignedShort(); //To change body of created methods use File | Settings | File Templates.
+ }
+
+ protected void writeBitfield(ByteBuffer buffer, byte bitfield0)
+ {
+ buffer.put(bitfield0);
+ }
+
+ protected void writeUnsignedShort(ByteBuffer buffer, int s)
+ {
+ EncodingUtils.writeUnsignedShort(buffer, s);
+ }
+
+ protected long readUnsignedInteger(ByteBuffer buffer)
+ {
+ return buffer.getUnsignedInt();
+ }
+ protected void writeUnsignedInteger(ByteBuffer buffer, long i)
+ {
+ EncodingUtils.writeUnsignedInteger(buffer, i);
+ }
+
+
+ protected short readUnsignedByte(ByteBuffer buffer)
+ {
+ return buffer.getUnsigned();
+ }
+
+ protected void writeUnsignedByte(ByteBuffer buffer, short unsignedByte)
+ {
+ EncodingUtils.writeUnsignedByte(buffer, unsignedByte);
+ }
+
+ protected long readTimestamp(ByteBuffer buffer)
+ {
+ return EncodingUtils.readTimestamp(buffer);
+ }
+
+ protected void writeTimestamp(ByteBuffer buffer, long t)
+ {
+ EncodingUtils.writeTimestamp(buffer, t);
+ }
}
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 1ff39ca790..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
@@ -22,6 +22,10 @@ package org.apache.qpid.framing;
import org.apache.mina.common.ByteBuffer;
+import java.util.Date;
+import java.util.Map;
+import java.math.BigDecimal;
+
/**
* AMQTypedValue combines together a native Java Object value, and an {@link AMQType}, as a fully typed AMQP parameter
* value. It provides the ability to read and write fully typed parameters to and from byte buffers. It also provides
@@ -113,4 +117,63 @@ public class AMQTypedValue
return _type.hashCode() ^ (_value == null ? 0 : _value.hashCode());
}
+
+ public static AMQTypedValue toTypedValue(Object val)
+ {
+ if(val == null)
+ {
+ return AMQType.VOID.asTypedValue(null);
+ }
+
+ Class klass = val.getClass();
+ if(klass == String.class)
+ {
+ return AMQType.ASCII_STRING.asTypedValue(val);
+ }
+ else if(klass == Character.class)
+ {
+ return AMQType.ASCII_CHARACTER.asTypedValue(val);
+ }
+ else if(klass == Integer.class)
+ {
+ return AMQType.INT.asTypedValue(val);
+ }
+ else if(klass == Long.class)
+ {
+ return AMQType.LONG.asTypedValue(val);
+ }
+ else if(klass == Float.class)
+ {
+ return AMQType.FLOAT.asTypedValue(val);
+ }
+ else if(klass == Double.class)
+ {
+ return AMQType.DOUBLE.asTypedValue(val);
+ }
+ else if(klass == Date.class)
+ {
+ return AMQType.TIMESTAMP.asTypedValue(val);
+ }
+ else if(klass == Byte.class)
+ {
+ return AMQType.BYTE.asTypedValue(val);
+ }
+ else if(klass == Boolean.class)
+ {
+ return AMQType.BOOLEAN.asTypedValue(val);
+ }
+ else if(klass == byte[].class)
+ {
+ return AMQType.BINARY.asTypedValue(val);
+ }
+ else if(klass == BigDecimal.class)
+ {
+ return AMQType.DECIMAL.asTypedValue(val);
+ }
+ else if(val instanceof Map)
+ {
+ return AMQType.FIELD_TABLE.asTypedValue(FieldTable.convertToFieldTable((Map)val));
+ }
+ return null;
+ }
}
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 47b5c02beb..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
@@ -27,6 +27,10 @@ import org.slf4j.LoggerFactory;
public class BasicContentHeaderProperties implements CommonContentHeaderProperties
{
+ //persistent & non-persistent constants, values as per JMS DeliveryMode
+ public static final int NON_PERSISTENT = 1;
+ public static final int PERSISTENT = 2;
+
private static final Logger _logger = LoggerFactory.getLogger(BasicContentHeaderProperties.class);
private static final AMQShortString ZERO_STRING = null;
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 ed01c91804..341238c667 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
@@ -131,9 +131,10 @@ public class FieldTable
}
else if ((_encodedForm != null) && (val != null))
{
- EncodingUtils.writeShortStringBytes(_encodedForm, key);
- val.writeToBuffer(_encodedForm);
-
+ // We have updated data to store in the buffer
+ // So clear the _encodedForm to allow it to be rebuilt later
+ // this is safer than simply appending to any existing buffer.
+ _encodedForm = null;
}
else if (val == null)
{
@@ -828,6 +829,7 @@ public class FieldTable
recalculateEncodedSize();
}
+
public static interface FieldTableElementProcessor
{
public boolean processElement(String propertyName, AMQTypedValue value);
@@ -904,10 +906,13 @@ public class FieldTable
}
}
+ public Object get(String key)
+ {
+ return get(new AMQShortString(key));
+ }
public Object get(AMQShortString key)
{
-
return getObject(key);
}
@@ -1184,4 +1189,24 @@ public class FieldTable
return _properties.equals(f._properties);
}
+
+ public static FieldTable convertToFieldTable(Map<String, Object> map)
+ {
+ if (map != null)
+ {
+ FieldTable table = new FieldTable();
+ for(Map.Entry<String,Object> entry : map.entrySet())
+ {
+ table.put(new AMQShortString(entry.getKey()), entry.getValue());
+ }
+
+ return table;
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+
}
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 3ac17e9204..ac21fe4243 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
@@ -20,12 +20,10 @@
*/
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.AMQException;
import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
public class ProtocolInitiation extends AMQDataBlock implements EncodableAMQDataBlock
{
@@ -53,13 +51,16 @@ public class ProtocolInitiation extends AMQDataBlock implements EncodableAMQData
_protocolMajor = protocolMajor;
_protocolMinor = protocolMinor;
}
-
+
public ProtocolInitiation(ProtocolVersion pv)
{
- this(AMQP_HEADER, CURRENT_PROTOCOL_CLASS, TCP_PROTOCOL_INSTANCE, pv.getMajorVersion(), pv.getMinorVersion());
+ this(AMQP_HEADER,
+ pv.equals(ProtocolVersion.v0_91) ? 0 : CURRENT_PROTOCOL_CLASS,
+ pv.equals(ProtocolVersion.v0_91) ? 0 : TCP_PROTOCOL_INSTANCE,
+ pv.equals(ProtocolVersion.v0_91) ? 9 : pv.getMajorVersion(),
+ pv.equals(ProtocolVersion.v0_91) ? 1 : pv.getMinorVersion());
}
-
public ProtocolInitiation(ByteBuffer in)
{
_protocolHeader = new byte[4];
@@ -71,6 +72,11 @@ public class ProtocolInitiation extends AMQDataBlock implements EncodableAMQData
_protocolMinor = in.get();
}
+ public void writePayload(org.apache.mina.common.ByteBuffer buffer)
+ {
+ writePayload(buffer.buf());
+ }
+
public long getSize()
{
return 4 + 1 + 1 + 1 + 1;
@@ -122,21 +128,15 @@ public class ProtocolInitiation extends AMQDataBlock implements EncodableAMQData
{
/**
*
- * @param session the session
* @param in input buffer
* @return true if we have enough data to decode the PI frame fully, false if more
* data is required
*/
- public boolean decodable(IoSession session, ByteBuffer in)
+ public boolean decodable(ByteBuffer in)
{
return (in.remaining() >= 8);
}
- public void decode(IoSession session, ByteBuffer in, ProtocolDecoderOutput out)
- {
- ProtocolInitiation pi = new ProtocolInitiation(in);
- out.write(pi);
- }
}
public ProtocolVersion checkVersion() throws AMQException
@@ -160,18 +160,33 @@ public class ProtocolInitiation extends AMQDataBlock implements EncodableAMQData
}
}
}
- if (_protocolClass != CURRENT_PROTOCOL_CLASS)
+
+ ProtocolVersion pv;
+
+ // Hack for 0-9-1 which changed how the header was defined
+ if(_protocolInstance == 0 && _protocolMajor == 9 && _protocolMinor == 1)
+ {
+ pv = ProtocolVersion.v0_91;
+ if (_protocolClass != 0)
+ {
+ throw new AMQProtocolClassException("Protocol class " + 0 + " was expected; received " +
+ _protocolClass, null);
+ }
+ }
+ else if (_protocolClass != CURRENT_PROTOCOL_CLASS)
{
throw new AMQProtocolClassException("Protocol class " + CURRENT_PROTOCOL_CLASS + " was expected; received " +
_protocolClass, null);
}
- if (_protocolInstance != TCP_PROTOCOL_INSTANCE)
+ else if (_protocolInstance != TCP_PROTOCOL_INSTANCE)
{
throw new AMQProtocolInstanceException("Protocol instance " + TCP_PROTOCOL_INSTANCE + " was expected; received " +
_protocolInstance, null);
}
-
- ProtocolVersion pv = new ProtocolVersion(_protocolMajor, _protocolMinor);
+ else
+ {
+ pv = new ProtocolVersion(_protocolMajor, _protocolMinor);
+ }
if (!pv.isSupported())
@@ -192,4 +207,5 @@ public class ProtocolInitiation extends AMQDataBlock implements EncodableAMQData
buffer.append(Integer.toHexString(_protocolMinor));
return buffer.toString();
}
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/abstraction/MessagePublishInfoImpl.java b/java/common/src/main/java/org/apache/qpid/framing/abstraction/MessagePublishInfoImpl.java
new file mode 100644
index 0000000000..e3d5da73da
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/framing/abstraction/MessagePublishInfoImpl.java
@@ -0,0 +1,85 @@
+/*
+ *
+ * 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.abstraction;
+
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.framing.AMQShortString;
+
+public class MessagePublishInfoImpl implements MessagePublishInfo
+{
+ private AMQShortString _exchange;
+ private boolean _immediate;
+ private boolean _mandatory;
+ private AMQShortString _routingKey;
+
+ public MessagePublishInfoImpl()
+ {
+ }
+
+ public MessagePublishInfoImpl(AMQShortString exchange, boolean immediate, boolean mandatory,
+ AMQShortString routingKey)
+ {
+ _exchange = exchange;
+ _immediate = immediate;
+ _mandatory = mandatory;
+ _routingKey = routingKey;
+ }
+
+ public AMQShortString getExchange()
+ {
+ return _exchange;
+ }
+
+ public void setExchange(AMQShortString exchange)
+ {
+ _exchange = exchange;
+ }
+
+ public boolean isImmediate()
+ {
+ return _immediate;
+ }
+
+ public void setImmediate(boolean immedate)
+ {
+ _immediate = immedate;
+ }
+
+ public boolean isMandatory()
+ {
+ return _mandatory;
+ }
+
+ public void setMandatory(boolean mandatory)
+ {
+ _mandatory = mandatory;
+ }
+
+ public AMQShortString getRoutingKey()
+ {
+ return _routingKey;
+ }
+
+ public void setRoutingKey(AMQShortString routingKey)
+ {
+ _routingKey = routingKey;
+ }
+}
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 0a1cedc4e6..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,10 +23,14 @@ 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);
ContentChunk convertToContentChunk(AMQBody body);
void configure();
+
+ AMQBody convertToBody(ByteBuffer buf);
}
diff --git a/java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/AMQMethodBody_0_9.java b/java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/AMQMethodBody_0_9.java
index 948f5baaf6..8d51343507 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/AMQMethodBody_0_9.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/amqp_0_9/AMQMethodBody_0_9.java
@@ -21,14 +21,6 @@
package org.apache.qpid.framing.amqp_0_9;
-import org.apache.qpid.framing.EncodingUtils;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.framing.AMQFrameDecodingException;
-import org.apache.qpid.framing.Content;
-
-import org.apache.mina.common.ByteBuffer;
-
public abstract class AMQMethodBody_0_9 extends org.apache.qpid.framing.AMQMethodBodyImpl
{
@@ -40,170 +32,6 @@ public abstract class AMQMethodBody_0_9 extends org.apache.qpid.framing.AMQMetho
public byte getMinor()
{
return 9;
- }
-
- public int getSize()
- {
- return 2 + 2 + getBodySize();
- }
-
- public void writePayload(ByteBuffer buffer)
- {
- EncodingUtils.writeUnsignedShort(buffer, getClazz());
- EncodingUtils.writeUnsignedShort(buffer, getMethod());
- writeMethodPayload(buffer);
- }
-
-
- protected byte readByte(ByteBuffer buffer)
- {
- return buffer.get();
- }
-
- protected AMQShortString readAMQShortString(ByteBuffer buffer)
- {
- return EncodingUtils.readAMQShortString(buffer);
- }
-
- protected int getSizeOf(AMQShortString string)
- {
- return EncodingUtils.encodedShortStringLength(string);
- }
-
- protected void writeByte(ByteBuffer buffer, byte b)
- {
- buffer.put(b);
- }
-
- protected void writeAMQShortString(ByteBuffer buffer, AMQShortString string)
- {
- EncodingUtils.writeShortStringBytes(buffer, string);
- }
-
- protected int readInt(ByteBuffer buffer)
- {
- return buffer.getInt();
- }
-
- protected void writeInt(ByteBuffer buffer, int i)
- {
- buffer.putInt(i);
- }
-
- protected FieldTable readFieldTable(ByteBuffer buffer) throws AMQFrameDecodingException
- {
- return EncodingUtils.readFieldTable(buffer);
- }
-
- protected int getSizeOf(FieldTable table)
- {
- return EncodingUtils.encodedFieldTableLength(table); //To change body of created methods use File | Settings | File Templates.
- }
-
- protected void writeFieldTable(ByteBuffer buffer, FieldTable table)
- {
- EncodingUtils.writeFieldTableBytes(buffer, table);
- }
-
- protected long readLong(ByteBuffer buffer)
- {
- return buffer.getLong();
- }
-
- protected void writeLong(ByteBuffer buffer, long l)
- {
- buffer.putLong(l);
- }
-
- protected int getSizeOf(byte[] response)
- {
- return (response == null) ? 4 :response.length + 4;
- }
-
- protected void writeBytes(ByteBuffer buffer, byte[] data)
- {
- EncodingUtils.writeBytes(buffer,data);
- }
-
- protected byte[] readBytes(ByteBuffer buffer)
- {
- return EncodingUtils.readBytes(buffer);
- }
-
- protected short readShort(ByteBuffer buffer)
- {
- return EncodingUtils.readShort(buffer);
- }
-
- protected void writeShort(ByteBuffer buffer, short s)
- {
- EncodingUtils.writeShort(buffer, s);
- }
-
- protected Content readContent(ByteBuffer buffer)
- {
- return null; //To change body of created methods use File | Settings | File Templates.
- }
-
- protected int getSizeOf(Content body)
- {
- return 0; //To change body of created methods use File | Settings | File Templates.
- }
-
- protected void writeContent(ByteBuffer buffer, Content body)
- {
- //To change body of created methods use File | Settings | File Templates.
- }
-
- protected byte readBitfield(ByteBuffer buffer)
- {
- return readByte(buffer); //To change body of created methods use File | Settings | File Templates.
- }
-
- protected int readUnsignedShort(ByteBuffer buffer)
- {
- return buffer.getUnsignedShort(); //To change body of created methods use File | Settings | File Templates.
- }
-
- protected void writeBitfield(ByteBuffer buffer, byte bitfield0)
- {
- buffer.put(bitfield0);
- }
-
- protected void writeUnsignedShort(ByteBuffer buffer, int s)
- {
- EncodingUtils.writeUnsignedShort(buffer, s);
- }
-
- protected long readUnsignedInteger(ByteBuffer buffer)
- {
- return buffer.getUnsignedInt();
- }
- protected void writeUnsignedInteger(ByteBuffer buffer, long i)
- {
- EncodingUtils.writeUnsignedInteger(buffer, i);
- }
-
-
- protected short readUnsignedByte(ByteBuffer buffer)
- {
- return buffer.getUnsigned();
- }
-
- protected void writeUnsignedByte(ByteBuffer buffer, short unsignedByte)
- {
- EncodingUtils.writeUnsignedByte(buffer, unsignedByte);
- }
-
- protected long readTimestamp(ByteBuffer buffer)
- {
- return EncodingUtils.readTimestamp(buffer);
- }
-
- protected void writeTimestamp(ByteBuffer buffer, long t)
- {
- EncodingUtils.writeTimestamp(buffer, t);
- }
-
+ }
}
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 fd5195eb6b..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
@@ -27,6 +27,7 @@ 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;
@@ -71,6 +72,11 @@ public class MethodConverter_0_9 extends AbstractMethodConverter implements Prot
}
+ public AMQBody convertToBody(java.nio.ByteBuffer buf)
+ {
+ return new ContentBody(ByteBuffer.wrap(buf));
+ }
+
public MessagePublishInfo convertToInfo(AMQMethodBody methodBody)
{
final BasicPublishBody publishBody = ((BasicPublishBody) methodBody);
@@ -78,7 +84,7 @@ public class MethodConverter_0_9 extends AbstractMethodConverter implements Prot
final AMQShortString exchange = publishBody.getExchange();
final AMQShortString routingKey = publishBody.getRoutingKey();
- return new MethodConverter_0_9.MessagePublishInfoImpl(exchange,
+ return new MessagePublishInfoImpl(exchange,
publishBody.getImmediate(),
publishBody.getMandatory(),
routingKey);
@@ -96,50 +102,6 @@ public class MethodConverter_0_9 extends AbstractMethodConverter implements Prot
}
- private static class MessagePublishInfoImpl implements MessagePublishInfo
- {
- private AMQShortString _exchange;
- private final boolean _immediate;
- private final boolean _mandatory;
- private final AMQShortString _routingKey;
-
- public MessagePublishInfoImpl(final AMQShortString exchange,
- final boolean immediate,
- final boolean mandatory,
- final AMQShortString routingKey)
- {
- _exchange = exchange;
- _immediate = immediate;
- _mandatory = mandatory;
- _routingKey = routingKey;
- }
-
- public AMQShortString getExchange()
- {
- return _exchange;
- }
-
- public void setExchange(AMQShortString exchange)
- {
- _exchange = exchange;
- }
-
- public boolean isImmediate()
- {
- return _immediate;
- }
-
- public boolean isMandatory()
- {
- return _mandatory;
- }
-
- public AMQShortString getRoutingKey()
- {
- return _routingKey;
- }
- }
-
private static class ContentChunk_0_9 implements ContentChunk
{
private final ContentBody _contentBodyChunk;
diff --git a/java/common/src/main/java/org/apache/qpid/framing/amqp_0_91/AMQMethodBody_0_91.java b/java/common/src/main/java/org/apache/qpid/framing/amqp_0_91/AMQMethodBody_0_91.java
new file mode 100644
index 0000000000..60b8a7e1a6
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/framing/amqp_0_91/AMQMethodBody_0_91.java
@@ -0,0 +1,37 @@
+/*
+ *
+ * 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.amqp_0_91;
+
+public abstract class AMQMethodBody_0_91 extends org.apache.qpid.framing.AMQMethodBodyImpl
+{
+
+ public byte getMajor()
+ {
+ return 0;
+ }
+
+ public byte getMinor()
+ {
+ return 91;
+ }
+
+} \ No newline at end of file
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
new file mode 100644
index 0000000000..6e330574bc
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/framing/amqp_0_91/MethodConverter_0_91.java
@@ -0,0 +1,132 @@
+/*
+ *
+ * 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.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;
+import org.apache.qpid.framing.abstraction.MessagePublishInfo;
+import org.apache.qpid.framing.abstraction.MessagePublishInfoImpl;
+import org.apache.qpid.framing.*;
+
+public class MethodConverter_0_91 extends AbstractMethodConverter implements ProtocolVersionMethodConverter
+{
+ private int _basicPublishClassId;
+ private int _basicPublishMethodId;
+
+ public MethodConverter_0_91()
+ {
+ super((byte)0,(byte)9);
+
+
+ }
+
+ public AMQBody convertToBody(ContentChunk contentChunk)
+ {
+ if(contentChunk instanceof ContentChunk_0_9)
+ {
+ return ((ContentChunk_0_9)contentChunk).toBody();
+ }
+ else
+ {
+ return new ContentBody(contentChunk.getData());
+ }
+ }
+
+ public ContentChunk convertToContentChunk(AMQBody body)
+ {
+ final ContentBody contentBodyChunk = (ContentBody) body;
+
+ return new ContentChunk_0_9(contentBodyChunk);
+
+ }
+
+ public void configure()
+ {
+
+ _basicPublishClassId = BasicPublishBodyImpl.CLASS_ID;
+ _basicPublishMethodId = BasicPublishBodyImpl.METHOD_ID;
+
+ }
+
+ public AMQBody convertToBody(java.nio.ByteBuffer buf)
+ {
+ return new ContentBody(ByteBuffer.wrap(buf));
+ }
+
+ public MessagePublishInfo convertToInfo(AMQMethodBody methodBody)
+ {
+ final BasicPublishBody publishBody = ((BasicPublishBody) methodBody);
+
+ final AMQShortString exchange = publishBody.getExchange();
+ final AMQShortString routingKey = publishBody.getRoutingKey();
+
+ return new MessagePublishInfoImpl(exchange,
+ publishBody.getImmediate(),
+ publishBody.getMandatory(),
+ routingKey);
+
+ }
+
+ public AMQMethodBody convertToBody(MessagePublishInfo info)
+ {
+
+ return new BasicPublishBodyImpl(0,
+ info.getExchange(),
+ info.getRoutingKey(),
+ info.isMandatory(),
+ info.isImmediate()) ;
+
+ }
+
+ private static class ContentChunk_0_9 implements ContentChunk
+ {
+ private final ContentBody _contentBodyChunk;
+
+ public ContentChunk_0_9(final ContentBody contentBodyChunk)
+ {
+ _contentBodyChunk = contentBodyChunk;
+ }
+
+ public int getSize()
+ {
+ return _contentBodyChunk.getSize();
+ }
+
+ public ByteBuffer getData()
+ {
+ return _contentBodyChunk.payload;
+ }
+
+ public void reduceToFit()
+ {
+ _contentBodyChunk.reduceBufferToFit();
+ }
+
+ public AMQBody toBody()
+ {
+ return _contentBodyChunk;
+ }
+ }
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/AMQMethodBody_8_0.java b/java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/AMQMethodBody_8_0.java
index e9b4447140..35645854c0 100644
--- a/java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/AMQMethodBody_8_0.java
+++ b/java/common/src/main/java/org/apache/qpid/framing/amqp_8_0/AMQMethodBody_8_0.java
@@ -21,14 +21,6 @@
package org.apache.qpid.framing.amqp_8_0;
-import org.apache.qpid.framing.EncodingUtils;
-import org.apache.qpid.framing.AMQShortString;
-import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.framing.AMQFrameDecodingException;
-import org.apache.qpid.framing.Content;
-
-import org.apache.mina.common.ByteBuffer;
-
public abstract class AMQMethodBody_8_0 extends org.apache.qpid.framing.AMQMethodBodyImpl
{
@@ -42,168 +34,7 @@ public abstract class AMQMethodBody_8_0 extends org.apache.qpid.framing.AMQMetho
return 0;
}
- public int getSize()
- {
- return 2 + 2 + getBodySize();
- }
-
- public void writePayload(ByteBuffer buffer)
- {
- EncodingUtils.writeUnsignedShort(buffer, getClazz());
- EncodingUtils.writeUnsignedShort(buffer, getMethod());
- writeMethodPayload(buffer);
- }
-
- protected byte readByte(ByteBuffer buffer)
- {
- return buffer.get();
- }
-
- protected AMQShortString readAMQShortString(ByteBuffer buffer)
- {
- return EncodingUtils.readAMQShortString(buffer);
- }
-
- protected int getSizeOf(AMQShortString string)
- {
- return EncodingUtils.encodedShortStringLength(string);
- }
-
- protected void writeByte(ByteBuffer buffer, byte b)
- {
- buffer.put(b);
- }
-
- protected void writeAMQShortString(ByteBuffer buffer, AMQShortString string)
- {
- EncodingUtils.writeShortStringBytes(buffer, string);
- }
-
- protected int readInt(ByteBuffer buffer)
- {
- return buffer.getInt();
- }
-
- protected void writeInt(ByteBuffer buffer, int i)
- {
- buffer.putInt(i);
- }
-
- protected FieldTable readFieldTable(ByteBuffer buffer) throws AMQFrameDecodingException
- {
- return EncodingUtils.readFieldTable(buffer);
- }
-
- protected int getSizeOf(FieldTable table)
- {
- return EncodingUtils.encodedFieldTableLength(table); //To change body of created methods use File | Settings | File Templates.
- }
-
- protected void writeFieldTable(ByteBuffer buffer, FieldTable table)
- {
- EncodingUtils.writeFieldTableBytes(buffer, table);
- }
-
- protected long readLong(ByteBuffer buffer)
- {
- return buffer.getLong();
- }
-
- protected void writeLong(ByteBuffer buffer, long l)
- {
- buffer.putLong(l);
- }
-
- protected int getSizeOf(byte[] response)
- {
- return (response == null) ? 4 : response.length + 4;
- }
-
- protected void writeBytes(ByteBuffer buffer, byte[] data)
- {
- EncodingUtils.writeBytes(buffer,data);
- }
-
- protected byte[] readBytes(ByteBuffer buffer)
- {
- return EncodingUtils.readBytes(buffer);
- }
-
- protected short readShort(ByteBuffer buffer)
- {
- return EncodingUtils.readShort(buffer);
- }
-
- protected void writeShort(ByteBuffer buffer, short s)
- {
- EncodingUtils.writeShort(buffer, s);
- }
-
- protected Content readContent(ByteBuffer buffer)
- {
- return null; //To change body of created methods use File | Settings | File Templates.
- }
-
- protected int getSizeOf(Content body)
- {
- return 0; //To change body of created methods use File | Settings | File Templates.
- }
-
- protected void writeContent(ByteBuffer buffer, Content body)
- {
- //To change body of created methods use File | Settings | File Templates.
- }
-
- protected byte readBitfield(ByteBuffer buffer)
- {
- return readByte(buffer); //To change body of created methods use File | Settings | File Templates.
- }
-
- protected int readUnsignedShort(ByteBuffer buffer)
- {
- return buffer.getUnsignedShort(); //To change body of created methods use File | Settings | File Templates.
- }
-
- protected void writeBitfield(ByteBuffer buffer, byte bitfield0)
- {
- buffer.put(bitfield0);
- }
-
- protected void writeUnsignedShort(ByteBuffer buffer, int s)
- {
- EncodingUtils.writeUnsignedShort(buffer, s);
- }
-
- protected long readUnsignedInteger(ByteBuffer buffer)
- {
- return buffer.getUnsignedInt();
- }
- protected void writeUnsignedInteger(ByteBuffer buffer, long i)
- {
- EncodingUtils.writeUnsignedInteger(buffer, i);
- }
-
-
- protected short readUnsignedByte(ByteBuffer buffer)
- {
- return buffer.getUnsigned();
- }
-
- protected void writeUnsignedByte(ByteBuffer buffer, short unsignedByte)
- {
- EncodingUtils.writeUnsignedByte(buffer, unsignedByte);
- }
-
- protected long readTimestamp(ByteBuffer buffer)
- {
- return EncodingUtils.readTimestamp(buffer);
- }
-
- protected void writeTimestamp(ByteBuffer buffer, long t)
- {
- EncodingUtils.writeTimestamp(buffer, t);
- }
}
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 299c655698..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
@@ -25,6 +25,7 @@ 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.AbstractMethodConverter;
+import org.apache.qpid.framing.abstraction.MessagePublishInfoImpl;
import org.apache.qpid.framing.amqp_8_0.BasicPublishBodyImpl;
import org.apache.qpid.framing.*;
@@ -79,6 +80,11 @@ public class MethodConverter_8_0 extends AbstractMethodConverter implements Prot
_basicPublishMethodId = BasicPublishBodyImpl.METHOD_ID;
}
+
+ public AMQBody convertToBody(java.nio.ByteBuffer buf)
+ {
+ return new ContentBody(ByteBuffer.wrap(buf));
+ }
public MessagePublishInfo convertToInfo(AMQMethodBody methodBody)
{
@@ -104,48 +110,4 @@ public class MethodConverter_8_0 extends AbstractMethodConverter implements Prot
info.isImmediate()) ;
}
-
- private static class MessagePublishInfoImpl implements MessagePublishInfo
- {
- private AMQShortString _exchange;
- private final boolean _immediate;
- private final boolean _mandatory;
- private final AMQShortString _routingKey;
-
- public MessagePublishInfoImpl(final AMQShortString exchange,
- final boolean immediate,
- final boolean mandatory,
- final AMQShortString routingKey)
- {
- _exchange = exchange;
- _immediate = immediate;
- _mandatory = mandatory;
- _routingKey = routingKey;
- }
-
- public AMQShortString getExchange()
- {
- return _exchange;
- }
-
- public void setExchange(AMQShortString exchange)
- {
- _exchange = exchange;
- }
-
- public boolean isImmediate()
- {
- return _immediate;
- }
-
- public boolean isMandatory()
- {
- return _mandatory;
- }
-
- public AMQShortString getRoutingKey()
- {
- return _routingKey;
- }
- }
}
diff --git a/java/common/src/main/java/org/apache/qpid/pool/Event.java b/java/common/src/main/java/org/apache/qpid/pool/Event.java
deleted file mode 100644
index 5996cbf89c..0000000000
--- a/java/common/src/main/java/org/apache/qpid/pool/Event.java
+++ /dev/null
@@ -1,155 +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.pool;
-
-import org.apache.mina.common.IoFilter;
-import org.apache.mina.common.IoSession;
-
-/**
- * An Event is a continuation, which is used to break a Mina filter chain and save the current point in the chain
- * for later processing. It is an abstract class, with different implementations for continuations of different kinds
- * of Mina events.
- *
- * <p/>These continuations are typically batched by {@link Job} for processing by a worker thread pool.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Process a continuation in the context of a Mina session.
- * </table>
- *
- * @todo Pull up _nextFilter and getNextFilter into Event, as all events use it. Inner classes need to be non-static
- * to use instance variables in the parent. Consequently they need to be non-inner to be instantiable outside of
- * the context of the outer Event class. The inner class construction used here is preventing common code re-use
- * (though not by a huge amount), but makes for an inelegent way of handling inheritance and doesn't seem like
- * a justifiable use of inner classes. Move the inner classes out into their own files.
- *
- * @todo Could make Event implement Runnable, FutureTask, or a custom Continuation interface, to clarify its status as
- * a continuation. Job is also a continuation, as is the job completion handler. Or, as Event is totally abstract,
- * it is really an interface, so could just drop it and use the continuation interface instead.
- */
-public abstract class Event
-{
- /**
- * Creates a continuation.
- */
- public Event()
- { }
-
- /**
- * Processes the continuation in the context of a Mina session.
- *
- * @param session The Mina session.
- */
- public abstract void process(IoSession session);
-
- /**
- * A continuation ({@link Event}) that takes a Mina messageReceived event, and passes it to a NextFilter.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Pass a Mina messageReceived event to a NextFilter. <td> {@link IoFilter.NextFilter}, {@link IoSession}
- * </table>
- */
- public static final class ReceivedEvent extends Event
- {
- private final Object _data;
-
- private final IoFilter.NextFilter _nextFilter;
-
- public ReceivedEvent(final IoFilter.NextFilter nextFilter, final Object data)
- {
- super();
- _nextFilter = nextFilter;
- _data = data;
- }
-
- public void process(IoSession session)
- {
- _nextFilter.messageReceived(session, _data);
- }
-
- public IoFilter.NextFilter getNextFilter()
- {
- return _nextFilter;
- }
- }
-
- /**
- * A continuation ({@link Event}) that takes a Mina filterWrite event, and passes it to a NextFilter.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Pass a Mina filterWrite event to a NextFilter.
- * <td> {@link IoFilter.NextFilter}, {@link IoFilter.WriteRequest}, {@link IoSession}
- * </table>
- */
- public static final class WriteEvent extends Event
- {
- private final IoFilter.WriteRequest _data;
- private final IoFilter.NextFilter _nextFilter;
-
- public WriteEvent(final IoFilter.NextFilter nextFilter, final IoFilter.WriteRequest data)
- {
- super();
- _nextFilter = nextFilter;
- _data = data;
- }
-
- public void process(IoSession session)
- {
- _nextFilter.filterWrite(session, _data);
- }
-
- public IoFilter.NextFilter getNextFilter()
- {
- return _nextFilter;
- }
- }
-
- /**
- * A continuation ({@link Event}) that takes a Mina sessionClosed event, and passes it to a NextFilter.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Pass a Mina sessionClosed event to a NextFilter. <td> {@link IoFilter.NextFilter}, {@link IoSession}
- * </table>
- */
- public static final class CloseEvent extends Event
- {
- private final IoFilter.NextFilter _nextFilter;
-
- public CloseEvent(final IoFilter.NextFilter nextFilter)
- {
- super();
- _nextFilter = nextFilter;
- }
-
- public void process(IoSession session)
- {
- _nextFilter.sessionClosed(session);
- }
-
- public IoFilter.NextFilter getNextFilter()
- {
- return _nextFilter;
- }
- }
-}
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
index 00da005515..82b600de88 100644
--- a/java/common/src/main/java/org/apache/qpid/pool/Job.java
+++ b/java/common/src/main/java/org/apache/qpid/pool/Job.java
@@ -21,9 +21,12 @@
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.apache.mina.common.IoSession;
+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.
@@ -52,35 +55,28 @@ import org.apache.mina.common.IoSession;
*/
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;
- /** The Mina session. */
- private final IoSession _session;
-
/** Holds the queue of events that make up the job. */
- private final java.util.Queue<Event> _eventQueue = new ConcurrentLinkedQueue<Event>();
+ 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();
- /** Holds the completion continuation, called upon completion of a run of the job. */
- private final JobCompletionHandler _completionHandler;
-
private final boolean _readJob;
- /**
- * Creates a new job that aggregates many continuations together.
- *
- * @param session The Mina session.
- * @param completionHandler The per job run, terminal continuation.
- * @param maxEvents The maximum number of aggregated continuations to process per run of the job.
- * @param readJob
- */
- Job(IoSession session, JobCompletionHandler completionHandler, int maxEvents, final boolean readJob)
+ private ReferenceCountingExecutorService _poolReference;
+
+ private final static Logger _logger = LoggerFactory.getLogger(Job.class);
+
+ public Job(ReferenceCountingExecutorService poolReference, int maxEvents, boolean readJob)
{
- _session = session;
- _completionHandler = completionHandler;
+ _poolReference = poolReference;
_maxEvents = maxEvents;
_readJob = readJob;
}
@@ -90,7 +86,7 @@ public class Job implements ReadWriteRunnable
*
* @param evt The continuation to enqueue.
*/
- void add(Event evt)
+ public void add(Runnable evt)
{
_eventQueue.add(evt);
}
@@ -104,14 +100,14 @@ public class Job implements ReadWriteRunnable
int i = _maxEvents;
while( --i != 0 )
{
- Event e = _eventQueue.poll();
+ Runnable e = _eventQueue.poll();
if (e == null)
{
return true;
}
else
{
- e.process(_session);
+ e.run();
}
}
return false;
@@ -153,40 +149,105 @@ public class Job implements ReadWriteRunnable
if(processAll())
{
deactivate();
- _completionHandler.completed(_session, this);
+ completed();
}
else
{
- _completionHandler.notCompleted(_session, this);
+ notCompleted();
}
}
- public boolean isReadJob()
- {
- return _readJob;
- }
-
public boolean isRead()
{
return _readJob;
}
-
- public boolean isWrite()
+
+ /**
+ * 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)
{
- return !_readJob;
- }
+ 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");
+ }
+ }
+ }
+
/**
- * Another interface for a continuation.
+ * 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.
*
- * @todo Get rid of this interface as there are other interfaces that could be used instead, such as FutureTask,
- * Runnable or a custom Continuation interface.
+ * @param session The Mina session to work in.
+ * @param job The job that completed.
*/
- static interface JobCompletionHandler
+ 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()
{
- public void completed(IoSession session, Job job);
+ final ExecutorService pool = _poolReference.getPool();
+
+ if(pool == null)
+ {
+ return;
+ }
- public void notCompleted(final IoSession session, final Job job);
+ 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/pool/PoolingFilter.java b/java/common/src/main/java/org/apache/qpid/pool/PoolingFilter.java
deleted file mode 100644
index a080cc7e04..0000000000
--- a/java/common/src/main/java/org/apache/qpid/pool/PoolingFilter.java
+++ /dev/null
@@ -1,491 +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.pool;
-
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import org.apache.mina.common.IdleStatus;
-import org.apache.mina.common.IoFilterAdapter;
-import org.apache.mina.common.IoSession;
-import org.apache.qpid.pool.Event.CloseEvent;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.concurrent.RejectedExecutionException;
-import java.util.concurrent.ExecutorService;
-
-/**
- * PoolingFilter, is a no-op pass through filter that hands all events down the Mina filter chain by default. As it
- * adds no behaviour by default to the filter chain, it is abstract.
- *
- * <p/>PoolingFilter provides a capability, available to sub-classes, to handle events in the chain asynchronously, by
- * adding them to a job. If a job is not active, adding an event to it activates it. If it is active, the event is
- * added to the job, which will run to completion and eventually process the event. The queue on the job itself acts as
- * a buffer between stages of the pipeline.
- *
- * <p/>There are two convenience methods, {@link #createAynschReadPoolingFilter} and
- * {@link #createAynschWritePoolingFilter}, for obtaining pooling filters that handle 'messageReceived' and
- * 'filterWrite' events, making it possible to process these event streams seperately.
- *
- * <p/>Pooling filters have a name, in order to distinguish different filter types. They set up a {@link Job} on the
- * Mina session they are working with, and store it in the session against their identifying name. This allows different
- * filters with different names to be set up on the same filter chain, on the same Mina session, that batch their
- * workloads in different jobs.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Implement default, pass through filter.
- * <tr><td> Create pooling filters and a specific thread pool. <td> {@link ReferenceCountingExecutorService}
- * <tr><td> Provide the ability to batch Mina events for asynchronous processing. <td> {@link Job}, {@link Event}
- * <tr><td> Provide a terminal continuation to keep jobs running till empty.
- * <td> {@link Job}, {@link Job.JobCompletionHandler}
- * </table>
- *
- * @todo The static helper methods are pointless. Could just call new.
- */
-public abstract class PoolingFilter extends IoFilterAdapter implements Job.JobCompletionHandler
-{
- /** Used for debugging purposes. */
- private static final Logger _logger = LoggerFactory.getLogger(PoolingFilter.class);
-
- /** Holds the managed reference to obtain the executor for the batched jobs. */
- private final ReferenceCountingExecutorService _poolReference;
-
- /** Used to hold a name for identifying differeny pooling filter types. */
- private final String _name;
-
- /** Defines the maximum number of events that will be batched into a single job. */
- static final int MAX_JOB_EVENTS = Integer.getInteger("amqj.server.read_write_pool.max_events", 10);
-
- private final int _maxEvents;
-
- private final boolean _readFilter;
-
- /**
- * Creates a named pooling filter, on the specified shared thread pool.
- *
- * @param refCountingPool The thread pool reference.
- * @param name The identifying name of the filter type.
- */
- public PoolingFilter(ReferenceCountingExecutorService refCountingPool, String name, int maxEvents, boolean readFilter)
- {
- _poolReference = refCountingPool;
- _name = name;
- _maxEvents = maxEvents;
- _readFilter = readFilter;
- }
-
- /**
- * Helper method to get an instance of a pooling filter that handles read events asynchronously.
- *
- * @param refCountingPool A managed reference to the thread pool.
- * @param name The filter types identifying name.
- *
- * @return A pooling filter for asynchronous read events.
- */
- public static PoolingFilter createAynschReadPoolingFilter(ReferenceCountingExecutorService refCountingPool, String name)
- {
- return new AsynchReadPoolingFilter(refCountingPool, name);
- }
-
- /**
- * Helper method to get an instance of a pooling filter that handles write events asynchronously.
- *
- * @param refCountingPool A managed reference to the thread pool.
- * @param name The filter types identifying name.
- *
- * @return A pooling filter for asynchronous write events.
- */
- public static PoolingFilter createAynschWritePoolingFilter(ReferenceCountingExecutorService refCountingPool, String name)
- {
- return new AsynchWritePoolingFilter(refCountingPool, name);
- }
-
- /**
- * Called by Mina to initialize this filter. Takes a reference to the thread pool.
- */
- public void init()
- {
- _logger.debug("Init called on PoolingFilter " + toString());
-
- // Called when the filter is initialised in the chain. If the reference count is
- // zero this acquire will initialise the pool.
- _poolReference.acquireExecutorService();
- }
-
- /**
- * Called by Mina to clean up this filter. Releases the reference to the thread pool.
- */
- public void destroy()
- {
- _logger.debug("Destroy called on PoolingFilter " + toString());
-
- // When the reference count gets to zero we release the executor service.
- _poolReference.releaseExecutorService();
- }
-
- /**
- * 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.
- */
- void fireAsynchEvent(Job job, Event event)
- {
-
- job.add(event);
-
- final ExecutorService pool = _poolReference.getPool();
-
- 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");
- }
- }
-
- }
-
- /**
- * Creates a Job on the Mina session, identified by this filters name, in which this filter places asynchronously
- * handled events.
- *
- * @param session The Mina session.
- */
- public void createNewJobForSession(IoSession session)
- {
- Job job = new Job(session, this, MAX_JOB_EVENTS,_readFilter);
- session.setAttribute(_name, job);
- }
-
- /**
- * Retrieves this filters Job, by this filters name, from the Mina session.
- *
- * @param session The Mina session.
- *
- * @return The Job for this filter to place asynchronous events into.
- */
- public Job getJobForSession(IoSession session)
- {
- return (Job) session.getAttribute(_name);
- }
-
- /**
- * 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(IoSession session, Job job)
- {
-
-
- if (!job.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 (job.activate())
- {
- try
- {
- pool.execute(job);
- }
- catch(RejectedExecutionException e)
- {
- _logger.warn("Thread pool shutdown while tasks still outstanding");
- }
-
- }
- }
- }
-
- public void notCompleted(IoSession session, Job job)
- {
- final ExecutorService pool = _poolReference.getPool();
-
- if(pool == null)
- {
- return;
- }
-
- try
- {
- pool.execute(job);
- }
- catch(RejectedExecutionException e)
- {
- _logger.warn("Thread pool shutdown while tasks still outstanding");
- }
-
- }
-
-
-
- /**
- * No-op pass through filter to the next filter in the chain.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- *
- * @throws Exception This method does not throw any exceptions, but has Exception in its signature to allow
- * overriding sub-classes the ability to.
- */
- public void sessionOpened(final NextFilter nextFilter, final IoSession session) throws Exception
- {
- nextFilter.sessionOpened(session);
- }
-
- /**
- * No-op pass through filter to the next filter in the chain.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- *
- * @throws Exception This method does not throw any exceptions, but has Exception in its signature to allow
- * overriding sub-classes the ability to.
- */
- public void sessionClosed(final NextFilter nextFilter, final IoSession session) throws Exception
- {
- nextFilter.sessionClosed(session);
- }
-
- /**
- * No-op pass through filter to the next filter in the chain.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- * @param status The session idle status.
- *
- * @throws Exception This method does not throw any exceptions, but has Exception in its signature to allow
- * overriding sub-classes the ability to.
- */
- public void sessionIdle(final NextFilter nextFilter, final IoSession session, final IdleStatus status) throws Exception
- {
- nextFilter.sessionIdle(session, status);
- }
-
- /**
- * No-op pass through filter to the next filter in the chain.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- * @param cause The underlying exception.
- *
- * @throws Exception This method does not throw any exceptions, but has Exception in its signature to allow
- * overriding sub-classes the ability to.
- */
- public void exceptionCaught(final NextFilter nextFilter, final IoSession session, final Throwable cause) throws Exception
- {
- nextFilter.exceptionCaught(session, cause);
- }
-
- /**
- * No-op pass through filter to the next filter in the chain.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- * @param message The message received.
- *
- * @throws Exception This method does not throw any exceptions, but has Exception in its signature to allow
- * overriding sub-classes the ability to.
- */
- public void messageReceived(final NextFilter nextFilter, final IoSession session, final Object message) throws Exception
- {
- nextFilter.messageReceived(session, message);
- }
-
- /**
- * No-op pass through filter to the next filter in the chain.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- * @param message The message sent.
- *
- * @throws Exception This method does not throw any exceptions, but has Exception in its signature to allow
- * overriding sub-classes the ability to.
- */
- public void messageSent(final NextFilter nextFilter, final IoSession session, final Object message) throws Exception
- {
- nextFilter.messageSent(session, message);
- }
-
- /**
- * No-op pass through filter to the next filter in the chain.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- * @param writeRequest The write request event.
- *
- * @throws Exception This method does not throw any exceptions, but has Exception in its signature to allow
- * overriding sub-classes the ability to.
- */
- public void filterWrite(final NextFilter nextFilter, final IoSession session, final WriteRequest writeRequest)
- throws Exception
- {
- nextFilter.filterWrite(session, writeRequest);
- }
-
- /**
- * No-op pass through filter to the next filter in the chain.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- *
- * @throws Exception This method does not throw any exceptions, but has Exception in its signature to allow
- * overriding sub-classes the ability to.
- */
- public void filterClose(NextFilter nextFilter, IoSession session) throws Exception
- {
- nextFilter.filterClose(session);
- }
-
- /**
- * No-op pass through filter to the next filter in the chain.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- *
- * @throws Exception This method does not throw any exceptions, but has Exception in its signature to allow
- * overriding sub-classes the ability to.
- */
- public void sessionCreated(NextFilter nextFilter, IoSession session) throws Exception
- {
- nextFilter.sessionCreated(session);
- }
-
- /**
- * Prints the filter types identifying name to a string, mainly for debugging purposes.
- *
- * @return The filter types identifying name.
- */
- public String toString()
- {
- return _name;
- }
-
- /**
- * AsynchReadPoolingFilter is a pooling filter that handles 'messageReceived' and 'sessionClosed' events
- * asynchronously.
- */
- public static class AsynchReadPoolingFilter extends PoolingFilter
- {
- /**
- * Creates a pooling filter that handles read events asynchronously.
- *
- * @param refCountingPool A managed reference to the thread pool.
- * @param name The filter types identifying name.
- */
- public AsynchReadPoolingFilter(ReferenceCountingExecutorService refCountingPool, String name)
- {
- super(refCountingPool, name, Integer.getInteger("amqj.server.read_write_pool.max_read_events", MAX_JOB_EVENTS),true);
- }
-
- /**
- * Hands off this event for asynchronous execution.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- * @param message The message received.
- */
- public void messageReceived(NextFilter nextFilter, final IoSession session, Object message)
- {
- Job job = getJobForSession(session);
- fireAsynchEvent(job, new Event.ReceivedEvent(nextFilter, message));
- }
-
- /**
- * Hands off this event for asynchronous execution.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- */
- public void sessionClosed(final NextFilter nextFilter, final IoSession session)
- {
- Job job = getJobForSession(session);
- fireAsynchEvent(job, new CloseEvent(nextFilter));
- }
- }
-
- /**
- * AsynchWritePoolingFilter is a pooling filter that handles 'filterWrite' and 'sessionClosed' events
- * asynchronously.
- */
- public static class AsynchWritePoolingFilter extends PoolingFilter
- {
- /**
- * Creates a pooling filter that handles write events asynchronously.
- *
- * @param refCountingPool A managed reference to the thread pool.
- * @param name The filter types identifying name.
- */
- public AsynchWritePoolingFilter(ReferenceCountingExecutorService refCountingPool, String name)
- {
- super(refCountingPool, name, Integer.getInteger("amqj.server.read_write_pool.max_write_events", MAX_JOB_EVENTS),false);
- }
-
- /**
- * Hands off this event for asynchronous execution.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- * @param writeRequest The write request event.
- */
- public void filterWrite(final NextFilter nextFilter, final IoSession session, final WriteRequest writeRequest)
- {
- Job job = getJobForSession(session);
- fireAsynchEvent(job, new Event.WriteEvent(nextFilter, writeRequest));
- }
-
- /**
- * Hands off this event for asynchronous execution.
- *
- * @param nextFilter The next filter in the chain.
- * @param session The Mina session.
- */
- public void sessionClosed(final NextFilter nextFilter, final IoSession session)
- {
- Job job = getJobForSession(session);
- fireAsynchEvent(job, new CloseEvent(nextFilter));
- }
- }
-}
diff --git a/java/common/src/main/java/org/apache/qpid/pool/ReadWriteRunnable.java b/java/common/src/main/java/org/apache/qpid/pool/ReadWriteRunnable.java
index ad04a923e1..140c93ca8d 100644
--- a/java/common/src/main/java/org/apache/qpid/pool/ReadWriteRunnable.java
+++ b/java/common/src/main/java/org/apache/qpid/pool/ReadWriteRunnable.java
@@ -23,5 +23,4 @@ package org.apache.qpid.pool;
public interface ReadWriteRunnable extends Runnable
{
boolean isRead();
- boolean isWrite();
}
diff --git a/java/common/src/main/java/org/apache/qpid/pool/ReadWriteThreadModel.java b/java/common/src/main/java/org/apache/qpid/pool/ReadWriteThreadModel.java
deleted file mode 100644
index 8cea70e597..0000000000
--- a/java/common/src/main/java/org/apache/qpid/pool/ReadWriteThreadModel.java
+++ /dev/null
@@ -1,102 +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.pool;
-
-import org.apache.mina.common.IoFilterChain;
-import org.apache.mina.common.ThreadModel;
-import org.apache.mina.filter.ReferenceCountingIoFilter;
-
-/**
- * ReadWriteThreadModel is a Mina i/o filter chain factory, which creates a filter chain with seperate filters to
- * handle read and write events. The seperate filters are {@link PoolingFilter}s, which have thread pools to handle
- * these events. The effect of this is that reading and writing may happen concurrently.
- *
- * <p/>Socket i/o will only happen with concurrent reads and writes if Mina has seperate selector threads for each.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Create a filter chain with seperate read and write thread pools for read/write Mina events.
- * <td> {@link PoolingFilter}
- * </table>
- */
-public class ReadWriteThreadModel implements ThreadModel
-{
- /** Holds the singleton instance of this factory. */
- private static final ReadWriteThreadModel _instance = new ReadWriteThreadModel();
-
- /** Holds the thread pooling filter for reads. */
- private final PoolingFilter _asynchronousReadFilter;
-
- /** Holds the thread pooloing filter for writes. */
- private final PoolingFilter _asynchronousWriteFilter;
-
- /**
- * Creates a new factory for concurrent i/o, thread pooling filter chain construction. This is private, so that
- * only a singleton instance of the factory is ever created.
- */
- private ReadWriteThreadModel()
- {
- final ReferenceCountingExecutorService executor = ReferenceCountingExecutorService.getInstance();
- _asynchronousReadFilter = PoolingFilter.createAynschReadPoolingFilter(executor, "AsynchronousReadFilter");
- _asynchronousWriteFilter = PoolingFilter.createAynschWritePoolingFilter(executor, "AsynchronousWriteFilter");
- }
-
- /**
- * Gets the singleton instance of this filter chain factory.
- *
- * @return The singleton instance of this filter chain factory.
- */
- public static ReadWriteThreadModel getInstance()
- {
- return _instance;
- }
-
- /**
- * Gets the read filter.
- *
- * @return The read filter.
- */
- public PoolingFilter getAsynchronousReadFilter()
- {
- return _asynchronousReadFilter;
- }
-
- /**
- * Gets the write filter.
- *
- * @return The write filter.
- */
- public PoolingFilter getAsynchronousWriteFilter()
- {
- return _asynchronousWriteFilter;
- }
-
- /**
- * Adds the concurrent read and write filters to a filter chain.
- *
- * @param chain The Mina filter chain to add to.
- */
- public void buildFilterChain(IoFilterChain chain)
- {
- chain.addFirst("AsynchronousReadFilter", new ReferenceCountingIoFilter(_asynchronousReadFilter));
- chain.addLast("AsynchronousWriteFilter", new ReferenceCountingIoFilter(_asynchronousWriteFilter));
- }
-}
diff --git a/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java b/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java
index ce9c6ae4cb..20a30b3ed3 100644
--- a/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java
+++ b/java/common/src/main/java/org/apache/qpid/pool/ReferenceCountingExecutorService.java
@@ -160,4 +160,13 @@ public class ReferenceCountingExecutorService
{
return _pool;
}
+
+ /**
+ * Return the ReferenceCount to this ExecutorService
+ * @return reference count
+ */
+ public int getReferenceCount()
+ {
+ return _refCount;
+ }
}
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
new file mode 100644
index 0000000000..31953ea6ab
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngine.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.protocol;
+
+import java.net.SocketAddress;
+
+import org.apache.qpid.framing.AMQDataBlock;
+import org.apache.qpid.transport.NetworkDriver;
+import org.apache.qpid.transport.Receiver;
+
+/**
+ * A ProtocolEngine is a Receiver for java.nio.ByteBuffers. It takes the data passed to it in the received
+ * decodes it and then process the result.
+ */
+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();
+
+ // Returns the local address of the NetworkDriver
+ SocketAddress getLocalAddress();
+
+ // Returns number of bytes written
+ long getWrittenBytes();
+
+ // Returns number of bytes read
+ long getReadBytes();
+
+ // Called by the NetworkDriver when the socket has been closed for reading
+ void closed();
+
+ // Called when the NetworkEngine has not written data for the specified period of time (will trigger a
+ // heartbeat)
+ void writerIdle();
+
+ // Called when the NetworkEngine has not read data for the specified period of time (will close the connection)
+ void readerIdle();
+
+
+} \ 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
new file mode 100644
index 0000000000..9df84eef90
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/protocol/ProtocolEngineFactory.java
@@ -0,0 +1,31 @@
+/*
+ *
+ * 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.protocol;
+
+import org.apache.qpid.transport.NetworkDriver;
+
+public interface ProtocolEngineFactory
+{
+
+ // Returns a new instance of a ProtocolEngine
+ ProtocolEngine newProtocolEngine(NetworkDriver networkDriver);
+
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/security/CallbackHandlerRegistry.java b/java/common/src/main/java/org/apache/qpid/security/CallbackHandlerRegistry.java
deleted file mode 100644
index 8c80a1b5b7..0000000000
--- a/java/common/src/main/java/org/apache/qpid/security/CallbackHandlerRegistry.java
+++ /dev/null
@@ -1,94 +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.security;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.qpid.QpidConfig;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class CallbackHandlerRegistry
-{
- private static final Logger _logger = LoggerFactory.getLogger(CallbackHandlerRegistry.class);
- private static CallbackHandlerRegistry _instance = new CallbackHandlerRegistry();
-
- private Map<String,Class> _mechanismToHandlerClassMap = new HashMap<String,Class>();
-
- private StringBuilder _mechanisms;
-
- public static CallbackHandlerRegistry getInstance()
- {
- return _instance;
- }
-
- public Class getCallbackHandlerClass(String mechanism)
- {
- return _mechanismToHandlerClassMap.get(mechanism);
- }
-
- public String getMechanisms()
- {
- return _mechanisms.toString();
- }
-
- private CallbackHandlerRegistry()
- {
- // first we register any Sasl client factories
- DynamicSaslRegistrar.registerSaslProviders();
- registerMechanisms();
- }
-
- private void registerMechanisms()
- {
- for (QpidConfig.SecurityMechanism securityMechanism: QpidConfig.get().getSecurityMechanisms() )
- {
- Class clazz = null;
- try
- {
- clazz = Class.forName(securityMechanism.getHandler());
- if (!AMQPCallbackHandler.class.isAssignableFrom(clazz))
- {
- _logger.debug("SASL provider " + clazz + " does not implement " + AMQPCallbackHandler.class +
- ". Skipping");
- continue;
- }
- _mechanismToHandlerClassMap.put(securityMechanism.getType(), clazz);
- if (_mechanisms == null)
- {
-
- _mechanisms = new StringBuilder();
- _mechanisms.append(securityMechanism.getType());
- }
- else
- {
- _mechanisms.append(" " + securityMechanism.getType());
- }
- }
- catch (ClassNotFoundException ex)
- {
- _logger.debug("Unable to load class " + securityMechanism.getHandler() + ". Skipping that SASL provider");
- continue;
- }
- }
- }
-}
diff --git a/java/common/src/main/java/org/apache/qpid/security/DynamicSaslRegistrar.java b/java/common/src/main/java/org/apache/qpid/security/DynamicSaslRegistrar.java
deleted file mode 100644
index 9f48ac96a3..0000000000
--- a/java/common/src/main/java/org/apache/qpid/security/DynamicSaslRegistrar.java
+++ /dev/null
@@ -1,74 +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.security;
-
-import java.security.Security;
-import java.util.Map;
-import java.util.TreeMap;
-
-import javax.security.sasl.SaslClientFactory;
-
-import org.apache.qpid.QpidConfig;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-public class DynamicSaslRegistrar
-{
- private static final Logger _logger = LoggerFactory.getLogger(DynamicSaslRegistrar.class);
-
- public static void registerSaslProviders()
- {
- Map<String, Class> factories = registerSaslClientFactories();
- if (factories.size() > 0)
- {
- Security.addProvider(new JCAProvider(factories));
- _logger.debug("Dynamic SASL provider added as a security provider");
- }
- }
-
- private static Map<String, Class> registerSaslClientFactories()
- {
- TreeMap<String, Class> factoriesToRegister =
- new TreeMap<String, Class>();
-
- for (QpidConfig.SaslClientFactory factory: QpidConfig.get().getSaslClientFactories())
- {
- String className = factory.getFactoryClass();
- try
- {
- Class clazz = Class.forName(className);
- if (!(SaslClientFactory.class.isAssignableFrom(clazz)))
- {
- _logger.debug("Class " + clazz + " does not implement " + SaslClientFactory.class + " - skipping");
- continue;
- }
- factoriesToRegister.put(factory.getType(), clazz);
- }
- catch (Exception ex)
- {
- _logger.debug("Error instantiating SaslClientFactory calss " + className + " - skipping");
- }
- }
- return factoriesToRegister;
- }
-
-
-}
diff --git a/java/common/src/main/java/org/apache/qpid/security/amqplain/AmqPlainSaslClient.java b/java/common/src/main/java/org/apache/qpid/security/amqplain/AmqPlainSaslClient.java
deleted file mode 100644
index 81acc66de4..0000000000
--- a/java/common/src/main/java/org/apache/qpid/security/amqplain/AmqPlainSaslClient.java
+++ /dev/null
@@ -1,105 +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.security.amqplain;
-
-import org.apache.qpid.framing.FieldTable;
-import org.apache.qpid.framing.FieldTableFactory;
-
-import javax.security.sasl.SaslClient;
-import javax.security.sasl.SaslException;
-import javax.security.auth.callback.CallbackHandler;
-import javax.security.auth.callback.NameCallback;
-import javax.security.auth.callback.PasswordCallback;
-import javax.security.auth.callback.Callback;
-
-/**
- * Implements the "AMQPlain" authentication protocol that uses FieldTables to send username and pwd.
- *
- */
-public class AmqPlainSaslClient implements SaslClient
-{
- /**
- * The name of this mechanism
- */
- public static final String MECHANISM = "AMQPLAIN";
-
- private CallbackHandler _cbh;
-
- public AmqPlainSaslClient(CallbackHandler cbh)
- {
- _cbh = cbh;
- }
-
- public String getMechanismName()
- {
- return "AMQPLAIN";
- }
-
- public boolean hasInitialResponse()
- {
- return true;
- }
-
- public byte[] evaluateChallenge(byte[] challenge) throws SaslException
- {
- // we do not care about the prompt or the default name
- NameCallback nameCallback = new NameCallback("prompt", "defaultName");
- PasswordCallback pwdCallback = new PasswordCallback("prompt", false);
- Callback[] callbacks = new Callback[]{nameCallback, pwdCallback};
- try
- {
- _cbh.handle(callbacks);
- }
- catch (Exception e)
- {
- throw new SaslException("Error handling SASL callbacks: " + e, e);
- }
- FieldTable table = FieldTableFactory.newFieldTable();
- table.setString("LOGIN", nameCallback.getName());
- table.setString("PASSWORD", new String(pwdCallback.getPassword()));
- return table.getDataAsBytes();
- }
-
- public boolean isComplete()
- {
- return true;
- }
-
- public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException
- {
- throw new SaslException("Not supported");
- }
-
- public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException
- {
- throw new SaslException("Not supported");
- }
-
- public Object getNegotiatedProperty(String propName)
- {
- return null;
- }
-
- public void dispose() throws SaslException
- {
- _cbh = null;
- }
-}
diff --git a/java/common/src/main/java/org/apache/qpid/security/amqplain/AmqPlainSaslClientFactory.java b/java/common/src/main/java/org/apache/qpid/security/amqplain/AmqPlainSaslClientFactory.java
deleted file mode 100644
index 6c66c87f4c..0000000000
--- a/java/common/src/main/java/org/apache/qpid/security/amqplain/AmqPlainSaslClientFactory.java
+++ /dev/null
@@ -1,62 +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.security.amqplain;
-
-import javax.security.sasl.SaslClientFactory;
-import javax.security.sasl.SaslClient;
-import javax.security.sasl.SaslException;
-import javax.security.sasl.Sasl;
-import javax.security.auth.callback.CallbackHandler;
-import java.util.Map;
-
-public class AmqPlainSaslClientFactory implements SaslClientFactory
-{
- public SaslClient createSaslClient(String[] mechanisms, String authorizationId, String protocol, String serverName, Map props, CallbackHandler cbh) throws SaslException
- {
- for (int i = 0; i < mechanisms.length; i++)
- {
- if (mechanisms[i].equals(AmqPlainSaslClient.MECHANISM))
- {
- if (cbh == null)
- {
- throw new SaslException("CallbackHandler must not be null");
- }
- return new AmqPlainSaslClient(cbh);
- }
- }
- return null;
- }
-
- public String[] getMechanismNames(Map props)
- {
- if (props.containsKey(Sasl.POLICY_NOPLAINTEXT) ||
- props.containsKey(Sasl.POLICY_NODICTIONARY) ||
- props.containsKey(Sasl.POLICY_NOACTIVE))
- {
- // returned array must be non null according to interface documentation
- return new String[0];
- }
- else
- {
- return new String[]{AmqPlainSaslClient.MECHANISM};
- }
- }
-}
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 950279fff1..e142d21e06 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
@@ -41,38 +41,74 @@ public class SSLContextFactory {
/**
* Path to the Java keystore file
*/
- private String _keystorePath;
+ private String _keyStorePath;
/**
* Password for the keystore
*/
- private String _keystorePassword;
+ private String _keyStorePassword;
/**
- * Cert type to use
+ * Cert type to use in keystore
*/
- private String _certType;
+ 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;
+
+
+
+ public SSLContextFactory(String trustStorePath, String trustStorePassword,
+ String trustStoreCertType)
+ {
+ this(trustStorePath,trustStorePassword,trustStoreCertType,
+ trustStorePath,trustStorePassword,trustStoreCertType);
+ }
+
+ /**
* 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 keystorePath, String keystorePassword,
- String certType)
+ public SSLContextFactory(String trustStorePath, String trustStorePassword, String trustStoreCertType,
+ String keyStorePath, String keyStorePassword, String keyStoreCertType)
{
- _keystorePath = keystorePath;
- _keystorePassword = keystorePassword;
- if (_keystorePassword.equals("none"))
+
+ _trustStorePath = trustStorePath;
+ _trustStorePassword = trustStorePassword;
+
+ if (_trustStorePassword.equals("none"))
+ {
+ _trustStorePassword = null;
+ }
+ _trustStoreCertType = trustStoreCertType;
+
+ _keyStorePath = keyStorePath;
+ _keyStorePassword = keyStorePassword;
+
+ if (_keyStorePassword.equals("none"))
{
- _keystorePassword = null;
+ _keyStorePassword = null;
}
- _certType = certType;
- if (keystorePath == null) {
- throw new IllegalArgumentException("Keystore path must be specified");
+ _keyStoreCertType = keyStoreCertType;
+
+ if (_trustStorePath == null) {
+ throw new IllegalArgumentException("A TrustStore path or KeyStore path must be specified");
}
- if (certType == null) {
+ if (_trustStoreCertType == null) {
throw new IllegalArgumentException("Cert type must be specified");
}
}
@@ -86,16 +122,18 @@ public class SSLContextFactory {
public SSLContext buildServerContext() throws GeneralSecurityException, IOException
{
// Create keystore
- KeyStore ks = getInitializedKeyStore();
+ KeyStore ks = getInitializedKeyStore(_keyStorePath,_keyStorePassword);
// Set up key manager factory to use our key store
- KeyManagerFactory kmf = KeyManagerFactory.getInstance(_certType);
- kmf.init(ks, _keystorePassword.toCharArray());
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance(_keyStoreCertType);
+ kmf.init(ks, _keyStorePassword.toCharArray());
+ KeyStore ts = 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");
- TrustManagerFactory tmf = TrustManagerFactory.getInstance(_certType);
- tmf.init(ks);
+ SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
return sslContext;
@@ -109,34 +147,34 @@ public class SSLContextFactory {
*/
public SSLContext buildClientContext() throws GeneralSecurityException, IOException
{
- KeyStore ks = getInitializedKeyStore();
- TrustManagerFactory tmf = TrustManagerFactory.getInstance(_certType);
+ KeyStore ks = getInitializedKeyStore(_trustStorePath,_trustStorePassword);
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance(_trustStoreCertType);
tmf.init(ks);
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
return context;
}
- private KeyStore getInitializedKeyStore() throws GeneralSecurityException, IOException
+ private KeyStore getInitializedKeyStore(String storePath, String storePassword) throws GeneralSecurityException, IOException
{
KeyStore ks = KeyStore.getInstance("JKS");
InputStream in = null;
try
{
- File f = new File(_keystorePath);
+ File f = new File(storePath);
if (f.exists())
{
in = new FileInputStream(f);
}
else
{
- in = Thread.currentThread().getContextClassLoader().getResourceAsStream(_keystorePath);
+ in = Thread.currentThread().getContextClassLoader().getResourceAsStream(storePath);
}
if (in == null)
{
- throw new IOException("Unable to load keystore resource: " + _keystorePath);
+ throw new IOException("Unable to load keystore resource: " + storePath);
}
- ks.load(in, _keystorePassword.toCharArray());
+ ks.load(in, storePassword.toCharArray());
}
finally
{
diff --git a/java/common/src/main/java/org/apache/qpid/thread/DefaultThreadFactory.java b/java/common/src/main/java/org/apache/qpid/thread/DefaultThreadFactory.java
new file mode 100644
index 0000000000..94869ab205
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/thread/DefaultThreadFactory.java
@@ -0,0 +1,18 @@
+package org.apache.qpid.thread;
+
+public class DefaultThreadFactory implements ThreadFactory
+{
+
+ public Thread createThread(Runnable r)
+ {
+ return new Thread(r);
+ }
+
+ public Thread createThread(Runnable r, int priority)
+ {
+ Thread t = new Thread(r);
+ t.setPriority(priority);
+ return t;
+ }
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/security/JCAProvider.java b/java/common/src/main/java/org/apache/qpid/thread/QpidThreadExecutor.java
index 033deb550c..38f60c04fe 100644
--- a/java/common/src/main/java/org/apache/qpid/security/JCAProvider.java
+++ b/java/common/src/main/java/org/apache/qpid/thread/QpidThreadExecutor.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,27 +18,25 @@
* under the License.
*
*/
-package org.apache.qpid.security;
-import java.security.Provider;
-import java.security.Security;
-import java.util.Map;
+package org.apache.qpid.thread;
-public class JCAProvider extends Provider
-{
- public JCAProvider(Map<String, Class> providerMap)
- {
- super("AMQSASLProvider", 1.0, "A JCA provider that registers all " +
- "AMQ SASL providers that want to be registered");
- register(providerMap);
- Security.addProvider(this);
- }
+import org.apache.qpid.thread.Threading;
- private void register(Map<String, Class> providerMap)
+import edu.emory.mathcs.backport.java.util.concurrent.Executor;
+
+public class QpidThreadExecutor implements Executor
+{
+ public void execute(Runnable command)
{
- for (Map.Entry<String, Class> me :providerMap.entrySet())
+ try
{
- put("SaslClientFactory." + me.getKey(), me.getValue().getName());
+ Threading.getThreadFactory().createThread(command).start();
+ }
+ catch(Exception e)
+ {
+ throw new RuntimeException("Error creating a thread using Qpid thread factory",e);
}
}
-} \ No newline at end of file
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/thread/RealtimeThreadFactory.java b/java/common/src/main/java/org/apache/qpid/thread/RealtimeThreadFactory.java
new file mode 100644
index 0000000000..b711f749f8
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/thread/RealtimeThreadFactory.java
@@ -0,0 +1,47 @@
+package org.apache.qpid.thread;
+
+import java.lang.reflect.Constructor;
+
+public class RealtimeThreadFactory implements ThreadFactory
+{
+ private Class threadClass;
+ private Constructor threadConstructor;
+ private Constructor priorityParameterConstructor;
+ private int defaultRTThreadPriority = 20;
+
+ public RealtimeThreadFactory() throws Exception
+ {
+ defaultRTThreadPriority = Integer.getInteger("qpid.rt_thread_priority",20);
+ threadClass = Class.forName("javax.realtime.RealtimeThread");
+
+ Class schedulingParametersClass = Class.forName("javax.realtime.SchedulingParameters");
+ Class releaseParametersClass = Class.forName("javax.realtime.ReleaseParameters");
+ Class memoryParametersClass = Class.forName("javax.realtime.MemoryParameters");
+ Class memoryAreaClass = Class.forName("javax.realtime.MemoryArea");
+ Class processingGroupParametersClass = Class.forName("javax.realtime.ProcessingGroupParameters");
+
+ Class[] paramTypes = new Class[]{schedulingParametersClass,
+ releaseParametersClass,
+ memoryParametersClass,
+ memoryAreaClass,
+ processingGroupParametersClass,
+ java.lang.Runnable.class};
+
+ threadConstructor = threadClass.getConstructor(paramTypes);
+
+ Class priorityParameterClass = Class.forName("javax.realtime.PriorityParameters");
+ priorityParameterConstructor = priorityParameterClass.getConstructor(new Class[]{int.class});
+ }
+
+ public Thread createThread(Runnable r) throws Exception
+ {
+ return createThread(r,defaultRTThreadPriority);
+ }
+
+ public Thread createThread(Runnable r, int priority) throws Exception
+ {
+ Object priorityParams = priorityParameterConstructor.newInstance(priority);
+ return (Thread)threadConstructor.newInstance(priorityParams,null,null,null,null,r);
+ }
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/thread/ThreadFactory.java b/java/common/src/main/java/org/apache/qpid/thread/ThreadFactory.java
new file mode 100644
index 0000000000..f9bcabfa3d
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/thread/ThreadFactory.java
@@ -0,0 +1,7 @@
+package org.apache.qpid.thread;
+
+public interface ThreadFactory
+{
+ public Thread createThread(Runnable r) throws Exception;
+ public Thread createThread(Runnable r, int priority) throws Exception;
+}
diff --git a/java/common/src/main/java/org/apache/qpid/thread/Threading.java b/java/common/src/main/java/org/apache/qpid/thread/Threading.java
new file mode 100644
index 0000000000..0fb113d22c
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/thread/Threading.java
@@ -0,0 +1,26 @@
+package org.apache.qpid.thread;
+
+public final class Threading
+{
+ private static ThreadFactory threadFactory;
+
+ static {
+ try
+ {
+ Class threadFactoryClass =
+ Class.forName(System.getProperty("qpid.thread_factory",
+ "org.apache.qpid.thread.DefaultThreadFactory"));
+
+ threadFactory = (ThreadFactory)threadFactoryClass.newInstance();
+ }
+ catch(Exception e)
+ {
+ throw new Error("Error occured while loading thread factory",e);
+ }
+ }
+
+ public static ThreadFactory getThreadFactory()
+ {
+ return threadFactory;
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/Binary.java b/java/common/src/main/java/org/apache/qpid/transport/Binary.java
index e6dedc536f..4e97855a6f 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/Binary.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/Binary.java
@@ -20,6 +20,10 @@
*/
package org.apache.qpid.transport;
+import java.nio.ByteBuffer;
+
+import static org.apache.qpid.transport.util.Functions.*;
+
/**
* Binary
@@ -51,6 +55,13 @@ public final class Binary
this(bytes, 0, bytes.length);
}
+ public final byte[] getBytes()
+ {
+ byte[] result = new byte[size];
+ System.arraycopy(bytes, offset, result, 0, size);
+ return result;
+ }
+
public final byte[] array()
{
return bytes;
@@ -126,4 +137,9 @@ public final class Binary
return true;
}
+ public String toString()
+ {
+ return str(ByteBuffer.wrap(bytes, offset, size));
+ }
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/Channel.java b/java/common/src/main/java/org/apache/qpid/transport/Channel.java
deleted file mode 100644
index d6b015930b..0000000000
--- a/java/common/src/main/java/org/apache/qpid/transport/Channel.java
+++ /dev/null
@@ -1,176 +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.transport.network.Frame;
-import org.apache.qpid.transport.util.Logger;
-
-import java.nio.ByteBuffer;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.locks.Lock;
-import java.util.concurrent.locks.ReentrantLock;
-
-import static org.apache.qpid.transport.network.Frame.*;
-import static org.apache.qpid.transport.util.Functions.*;
-
-
-/**
- * Channel
- *
- * @author Rafael H. Schloming
- */
-
-public class Channel extends Invoker
- implements Receiver<ProtocolEvent>, ProtocolDelegate<Void>
-{
-
- private static final Logger log = Logger.get(Channel.class);
-
- final private Connection connection;
- final private int channel;
- final private MethodDelegate<Channel> delegate;
- final private SessionDelegate sessionDelegate;
- // session may be null
- private Session session;
-
- public Channel(Connection connection, int channel, SessionDelegate delegate)
- {
- this.connection = connection;
- this.channel = channel;
- this.delegate = new ChannelDelegate();
- this.sessionDelegate = delegate;
- }
-
- public Connection getConnection()
- {
- return connection;
- }
-
- public void received(ProtocolEvent event)
- {
- event.delegate(null, this);
- }
-
- public void init(Void v, ProtocolHeader hdr)
- {
- connection.getConnectionDelegate().init(this, hdr);
- }
-
- public void control(Void v, Method method)
- {
- switch (method.getEncodedTrack())
- {
- case L1:
- method.dispatch(this, connection.getConnectionDelegate());
- break;
- case L2:
- method.dispatch(this, delegate);
- break;
- case L3:
- method.delegate(session, sessionDelegate);
- break;
- default:
- throw new IllegalStateException
- ("unknown track: " + method.getEncodedTrack());
- }
- }
-
- public void command(Void v, Method method)
- {
- method.delegate(session, sessionDelegate);
- }
-
- public void error(Void v, ProtocolError error)
- {
- throw new RuntimeException(error.getMessage());
- }
-
- public void exception(Throwable t)
- {
- session.exception(t);
- }
-
- public void closed()
- {
- log.debug("channel closed: ", this);
- if (session != null)
- {
- session.closed();
- }
- connection.removeChannel(channel);
- }
-
- public int getEncodedChannel() {
- return channel;
- }
-
- public Session getSession()
- {
- return session;
- }
-
- void setSession(Session session)
- {
- this.session = session;
- }
-
- void closeCode(ConnectionClose close)
- {
- if (session != null)
- {
- session.closeCode(close);
- }
- }
-
- private void emit(ProtocolEvent event)
- {
- event.setChannel(channel);
- connection.send(event);
- }
-
- public void method(Method m)
- {
- emit(m);
-
- if (!m.isBatch())
- {
- connection.flush();
- }
- }
-
- protected void invoke(Method m)
- {
- method(m);
- }
-
- protected <T> Future<T> invoke(Method m, Class<T> cls)
- {
- throw new UnsupportedOperationException();
- }
-
- public String toString()
- {
- return String.format("%s:%s", connection, channel);
- }
-
-}
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 bbdadfadb9..bd03c3e242 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,21 +20,152 @@
*/
package org.apache.qpid.transport;
+import static org.apache.qpid.transport.Connection.State.OPEN;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+
+import org.apache.qpid.security.UsernamePasswordCallbackHandler;
+import org.apache.qpid.transport.util.Logger;
+
/**
* ClientDelegate
*
*/
-public abstract class ClientDelegate extends ConnectionDelegate
+public class ClientDelegate extends ConnectionDelegate
{
+ private static final Logger log = Logger.get(ClientDelegate.class);
+
+ private String vhost;
+ private String username;
+ private String password;
+ private String[] saslMechs;
+ private String protocol;
+ private String serverName;
+
+ public ClientDelegate(String vhost, String username, String password,String saslMechs)
+ {
+ this.vhost = vhost;
+ this.username = username;
+ this.password = password;
+ this.saslMechs = saslMechs.split(" ");
+
+ // Looks kinda of silly but the Sun SASL Kerberos client uses the
+ // protocol + servername as the service key.
+ this.protocol = System.getProperty("qpid.sasl_protocol","AMQP");
+ this.serverName = System.getProperty("qpid.sasl_server_name","localhost");
+ }
- public void init(Channel ch, ProtocolHeader hdr)
+ public void init(Connection conn, ProtocolHeader hdr)
{
- if (hdr.getMajor() != 0 && hdr.getMinor() != 10)
+ if (!(hdr.getMajor() == 0 && hdr.getMinor() == 10))
{
- throw new ProtocolVersionException(hdr.getMajor(), hdr.getMinor());
+ conn.exception(new ProtocolVersionException(hdr.getMajor(), hdr.getMinor()));
}
}
+ @Override public void connectionStart(Connection conn, ConnectionStart start)
+ {
+ Map clientProperties = new HashMap();
+ clientProperties.put("qpid.session_flow", 1);
+
+ List<Object> mechanisms = start.getMechanisms();
+ if (mechanisms == null || mechanisms.isEmpty())
+ {
+ conn.connectionStartOk
+ (clientProperties, null, null, conn.getLocale());
+ return;
+ }
+
+ String[] mechs = new String[mechanisms.size()];
+ mechanisms.toArray(mechs);
+
+ try
+ {
+ UsernamePasswordCallbackHandler handler =
+ new UsernamePasswordCallbackHandler();
+ handler.initialise(username, password);
+ SaslClient sc = Sasl.createSaslClient
+ (saslMechs, null, protocol, serverName, null, handler);
+ conn.setSaslClient(sc);
+
+ byte[] response = sc.hasInitialResponse() ?
+ sc.evaluateChallenge(new byte[0]) : null;
+ conn.connectionStartOk
+ (clientProperties, sc.getMechanismName(), response,
+ conn.getLocale());
+ }
+ catch (SaslException e)
+ {
+ conn.exception(e);
+ }
+ }
+
+ @Override public void connectionSecure(Connection conn, ConnectionSecure secure)
+ {
+ SaslClient sc = conn.getSaslClient();
+ try
+ {
+ byte[] response = sc.evaluateChallenge(secure.getChallenge());
+ conn.connectionSecureOk(response);
+ }
+ catch (SaslException e)
+ {
+ conn.exception(e);
+ }
+ }
+
+ @Override public void connectionTune(Connection conn, ConnectionTune tune)
+ {
+ conn.setChannelMax(tune.getChannelMax());
+ int hb_interval = calculateHeartbeatInterval(conn,
+ tune.getHeartbeatMin(),
+ tune.getHeartbeatMax()
+ );
+ conn.connectionTuneOk(tune.getChannelMax(),
+ tune.getMaxFrameSize(),
+ hb_interval);
+ conn.setIdleTimeout(hb_interval*1000);
+ conn.connectionOpen(vhost, null, Option.INSIST);
+ }
+
+ @Override public void connectionOpenOk(Connection conn, ConnectionOpenOk ok)
+ {
+ conn.setState(OPEN);
+ }
+
+ @Override public void connectionRedirect(Connection conn, ConnectionRedirect redir)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override public void connectionHeartbeat(Connection conn, ConnectionHeartbeat hearbeat)
+ {
+ conn.connectionHeartbeat();
+ }
+
+ /**
+ * Currently the spec specified the min and max for heartbeat using secs
+ */
+ private int calculateHeartbeatInterval(Connection conn,int min, int max)
+ {
+ long l = conn.getIdleTimeout()/1000;
+ if (l !=0 && l >= min && l <= max)
+ {
+ return (int)l;
+ }
+ else
+ {
+ log.warn("Ignoring the idle timeout %s set by the connection," +
+ " using the brokers max value %s", l,max);
+ return max;
+ }
+ }
}
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 68b9b209bb..773746af79 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
@@ -20,14 +20,23 @@
*/
package org.apache.qpid.transport;
+import org.apache.qpid.transport.network.ConnectionBinding;
+import org.apache.qpid.transport.network.io.IoTransport;
import org.apache.qpid.transport.util.Logger;
+import org.apache.qpid.transport.util.Waiter;
+import org.apache.qpid.util.Strings;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.nio.ByteBuffer;
+import java.util.UUID;
+
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslServer;
+
+import static org.apache.qpid.transport.Connection.State.*;
/**
@@ -40,27 +49,222 @@ import java.nio.ByteBuffer;
* short instead of Short
*/
-public class Connection
+public class Connection extends ConnectionInvoker
implements Receiver<ProtocolEvent>, Sender<ProtocolEvent>
{
private static final Logger log = Logger.get(Connection.class);
- final private Sender<ProtocolEvent> sender;
- final private ConnectionDelegate delegate;
+ public enum State { NEW, CLOSED, OPENING, OPEN, CLOSING, CLOSE_RCVD }
+
+ class DefaultConnectionListener implements ConnectionListener
+ {
+ public void opened(Connection conn) {}
+ public void exception(Connection conn, ConnectionException exception)
+ {
+ log.error(exception, "connection exception");
+ }
+ public void closed(Connection conn) {}
+ }
+
+ private ConnectionDelegate delegate;
+ private Sender<ProtocolEvent> sender;
+
+ final private Map<Binary,Session> sessions = new HashMap<Binary,Session>();
+ final private Map<Integer,Session> channels = new HashMap<Integer,Session>();
+
+ private State state = NEW;
+ final private Object lock = new Object();
+ private long timeout = 60000;
+ private ConnectionListener listener = new DefaultConnectionListener();
+ private ConnectionException error = null;
+
private int channelMax = 1;
+ private String locale;
+ private SaslServer saslServer;
+ private SaslClient saslClient;
+ private long idleTimeout = 0;
+ private String _authorizationID;
+
// want to make this final
private int _connectionId;
- final private Map<Integer,Channel> channels = new HashMap<Integer,Channel>();
+ public Connection() {}
- public Connection(Sender<ProtocolEvent> sender,
- ConnectionDelegate delegate)
+ public void setConnectionDelegate(ConnectionDelegate delegate)
{
- this.sender = sender;
this.delegate = delegate;
}
+ public void setConnectionListener(ConnectionListener listener)
+ {
+ if (listener == null)
+ {
+ this.listener = new DefaultConnectionListener();
+ }
+ else
+ {
+ this.listener = listener;
+ }
+ }
+
+ public Sender<ProtocolEvent> getSender()
+ {
+ return sender;
+ }
+
+ public void setSender(Sender<ProtocolEvent> sender)
+ {
+ this.sender = sender;
+ sender.setIdleTimeout(idleTimeout);
+ }
+
+ protected void setState(State state)
+ {
+ synchronized (lock)
+ {
+ this.state = state;
+ lock.notifyAll();
+ }
+ }
+
+ void setLocale(String locale)
+ {
+ this.locale = locale;
+ }
+
+ String getLocale()
+ {
+ return locale;
+ }
+
+ void setSaslServer(SaslServer saslServer)
+ {
+ this.saslServer = saslServer;
+ }
+
+ SaslServer getSaslServer()
+ {
+ return saslServer;
+ }
+
+ void setSaslClient(SaslClient saslClient)
+ {
+ this.saslClient = saslClient;
+ }
+
+ SaslClient getSaslClient()
+ {
+ return saslClient;
+ }
+
+ public void connect(String host, int port, String vhost, String username, String password)
+ {
+ connect(host, port, vhost, username, password, false);
+ }
+
+ public void connect(String host, int port, String vhost, String username, String password, boolean ssl)
+ {
+ connect(host, port, vhost, username, password, ssl,"PLAIN");
+ }
+
+ public void connect(String host, int port, String vhost, String username, String password, boolean ssl,String saslMechs)
+ {
+ synchronized (lock)
+ {
+ state = OPENING;
+
+ delegate = new ClientDelegate(vhost, username, password,saslMechs);
+
+ IoTransport.connect(host, port, ConnectionBinding.get(this), ssl);
+ send(new ProtocolHeader(1, 0, 10));
+
+ Waiter w = new Waiter(lock, timeout);
+ while (w.hasTime() && state == OPENING && error == null)
+ {
+ w.await();
+ }
+
+ if (error != null)
+ {
+ ConnectionException t = error;
+ error = null;
+ try
+ {
+ close();
+ }
+ catch (ConnectionException ce)
+ {
+ if (!(t instanceof ProtocolVersionException))
+ {
+ throw ce;
+ }
+ }
+ t.rethrow();
+ }
+
+ switch (state)
+ {
+ case OPENING:
+ close();
+ throw new ConnectionException("connect() timed out");
+ case OPEN:
+ break;
+ case CLOSED:
+ throw new ConnectionException("connect() aborted");
+ default:
+ throw new IllegalStateException(String.valueOf(state));
+ }
+ }
+
+ listener.opened(this);
+ }
+
+ public Session createSession()
+ {
+ return createSession(0);
+ }
+
+ public Session createSession(long expiry)
+ {
+ return createSession(UUID.randomUUID().toString(), expiry);
+ }
+
+ public Session createSession(String name)
+ {
+ return createSession(name, 0);
+ }
+
+ public Session createSession(String name, long expiry)
+ {
+ return createSession(Strings.toUTF8(name), expiry);
+ }
+
+ public Session createSession(byte[] name, long expiry)
+ {
+ return createSession(new Binary(name), expiry);
+ }
+
+ public Session createSession(Binary name, long expiry)
+ {
+ synchronized (lock)
+ {
+ Session ssn = new Session(this, name, expiry);
+ sessions.put(name, ssn);
+ map(ssn);
+ ssn.attach();
+ return ssn;
+ }
+ }
+
+ void removeSession(Session ssn)
+ {
+ synchronized (lock)
+ {
+ sessions.remove(ssn.getName());
+ }
+ }
+
public void setConnectionId(int id)
{
_connectionId = id;
@@ -79,14 +283,18 @@ public class Connection
public void received(ProtocolEvent event)
{
log.debug("RECV: [%s] %s", this, event);
- Channel channel = getChannel(event.getChannel());
- channel.received(event);
+ event.delegate(this, delegate);
}
public void send(ProtocolEvent event)
{
log.debug("SEND: [%s] %s", this, event);
- sender.send(event);
+ Sender s = sender;
+ if (s == null)
+ {
+ throw new ConnectionException("connection closed");
+ }
+ s.send(event);
}
public void flush()
@@ -95,6 +303,30 @@ public class Connection
sender.flush();
}
+ protected void invoke(Method method)
+ {
+ method.setChannel(0);
+ send(method);
+ if (!method.isBatch())
+ {
+ flush();
+ }
+ }
+
+ public void dispatch(Method method)
+ {
+ Session ssn = getSession(method.getChannel());
+ if(ssn != null)
+ {
+ ssn.received(method);
+ }
+ else
+ {
+ throw new ProtocolViolationException(
+ "Received frames for an already dettached session", null);
+ }
+ }
+
public int getChannelMax()
{
return channelMax;
@@ -105,15 +337,16 @@ public class Connection
channelMax = max;
}
- public Channel getChannel()
+ private int map(Session ssn)
{
- synchronized (channels)
+ synchronized (lock)
{
for (int i = 0; i < getChannelMax(); i++)
{
if (!channels.containsKey(i))
{
- return getChannel(i);
+ map(ssn, i);
+ return i;
}
}
@@ -121,61 +354,195 @@ public class Connection
}
}
- public Channel getChannel(int number)
+ void map(Session ssn, int channel)
+ {
+ synchronized (lock)
+ {
+ channels.put(channel, ssn);
+ ssn.setChannel(channel);
+ }
+ }
+
+ void unmap(Session ssn)
+ {
+ synchronized (lock)
+ {
+ channels.remove(ssn.getChannel());
+ }
+ }
+
+ Session getSession(int channel)
+ {
+ synchronized (lock)
+ {
+ return channels.get(channel);
+ }
+ }
+
+ public void resume()
{
- synchronized (channels)
+ synchronized (lock)
{
- Channel channel = channels.get(number);
- if (channel == null)
+ for (Session ssn : sessions.values())
{
- channel = new Channel(this, number, delegate.getSessionDelegate());
- channels.put(number, channel);
+ map(ssn);
+ ssn.attach();
+ ssn.resume();
}
- return channel;
}
}
- void removeChannel(int number)
+ public void exception(ConnectionException e)
{
- synchronized (channels)
+ synchronized (lock)
{
- channels.remove(number);
+ switch (state)
+ {
+ case OPENING:
+ case CLOSING:
+ error = e;
+ lock.notifyAll();
+ return;
+ }
}
+
+ listener.exception(this, e);
}
public void exception(Throwable t)
{
- delegate.exception(t);
+ exception(new ConnectionException(t));
}
void closeCode(ConnectionClose close)
{
- synchronized (channels)
+ synchronized (lock)
{
- for (Channel ch : channels.values())
+ for (Session ssn : channels.values())
{
- ch.closeCode(close);
+ ssn.closeCode(close);
+ }
+ ConnectionCloseCode code = close.getReplyCode();
+ if (code != ConnectionCloseCode.NORMAL)
+ {
+ exception(new ConnectionException(close));
}
}
}
public void closed()
{
+ if (state == OPEN)
+ {
+ exception(new ConnectionException("connection aborted"));
+ }
+
log.debug("connection closed: %s", this);
- synchronized (channels)
+
+ synchronized (lock)
{
- List<Channel> values = new ArrayList<Channel>(channels.values());
- for (Channel ch : values)
+ List<Session> values = new ArrayList<Session>(channels.values());
+ for (Session ssn : values)
+ {
+ ssn.closed();
+ }
+
+ try
+ {
+ sender.close();
+ }
+ catch(Exception e)
{
- ch.closed();
+ // ignore.
}
+ sender = null;
+ setState(CLOSED);
}
- delegate.closed();
+
+ listener.closed(this);
}
public void close()
{
- sender.close();
+ synchronized (lock)
+ {
+ switch (state)
+ {
+ case OPEN:
+ state = CLOSING;
+ connectionClose(ConnectionCloseCode.NORMAL, null);
+ Waiter w = new Waiter(lock, timeout);
+ while (w.hasTime() && state == CLOSING && error == null)
+ {
+ w.await();
+ }
+
+ if (error != null)
+ {
+ close();
+ throw new ConnectionException(error);
+ }
+
+ switch (state)
+ {
+ case CLOSING:
+ close();
+ throw new ConnectionException("close() timed out");
+ case CLOSED:
+ break;
+ default:
+ throw new IllegalStateException(String.valueOf(state));
+ }
+ break;
+ case CLOSED:
+ break;
+ default:
+ if (sender != null)
+ {
+ sender.close();
+ w = new Waiter(lock, timeout);
+ while (w.hasTime() && sender != null && error == null)
+ {
+ w.await();
+ }
+
+ if (error != null)
+ {
+ throw new ConnectionException(error);
+ }
+
+ if (sender != null)
+ {
+ throw new ConnectionException("close() timed out");
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ public void setIdleTimeout(long l)
+ {
+ idleTimeout = l;
+ if (sender != null)
+ {
+ sender.setIdleTimeout(l);
+ }
+ }
+
+ public long getIdleTimeout()
+ {
+ return idleTimeout;
+ }
+
+ public void setAuthorizationID(String authorizationID)
+ {
+ _authorizationID = authorizationID;
+ }
+
+ public String getAuthorizationID()
+ {
+ return _authorizationID;
}
public String toString()
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 2aa1db7b28..9ef7a47e1b 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
@@ -22,22 +22,7 @@ package org.apache.qpid.transport;
import org.apache.qpid.transport.util.Logger;
-import org.apache.qpid.SecurityHelper;
-import org.apache.qpid.QpidException;
-
-import java.io.UnsupportedEncodingException;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.Lock;
-
-import javax.security.sasl.Sasl;
-import javax.security.sasl.SaslClient;
-import javax.security.sasl.SaslException;
-import javax.security.sasl.SaslServer;
+import static org.apache.qpid.transport.Connection.State.*;
/**
@@ -52,236 +37,67 @@ import javax.security.sasl.SaslServer;
*
* the connectionClose is kind of different for both sides
*/
-public abstract class ConnectionDelegate extends MethodDelegate<Channel>
+public abstract class ConnectionDelegate
+ extends MethodDelegate<Connection>
+ implements ProtocolDelegate<Connection>
{
private static final Logger log = Logger.get(ConnectionDelegate.class);
- private String _username = "guest";
- private String _password = "guest";;
- private String _mechanism;
- private String _virtualHost;
- private SaslClient saslClient;
- private SaslServer saslServer;
- private String _locale = "utf8";
- private int maxFrame = 64*1024;
- private Condition _negotiationComplete;
- private Lock _negotiationCompleteLock;
-
- public abstract SessionDelegate getSessionDelegate();
-
- public abstract void exception(Throwable t);
-
- public abstract void closed();
-
- public void setCondition(Lock negotiationCompleteLock,Condition negotiationComplete)
+ public void control(Connection conn, Method method)
{
- _negotiationComplete = negotiationComplete;
- _negotiationCompleteLock = negotiationCompleteLock;
+ method.dispatch(conn, this);
}
- public void init(Channel ch, ProtocolHeader hdr)
+ public void command(Connection conn, Method method)
{
- ch.getConnection().send(new ProtocolHeader (1, hdr.getMajor(), hdr.getMinor()));
- List<Object> plain = new ArrayList<Object>();
- plain.add("PLAIN");
- List<Object> utf8 = new ArrayList<Object>();
- utf8.add("utf8");
- ch.connectionStart(null, plain, utf8);
+ method.dispatch(conn, this);
}
- // ----------------------------------------------
- // Client side
- //-----------------------------------------------
- @Override public void connectionStart(Channel context, ConnectionStart struct)
+ public void error(Connection conn, ProtocolError error)
{
- String mechanism = null;
- byte[] response = null;
- try
- {
- mechanism = SecurityHelper.chooseMechanism(struct.getMechanisms());
- saslClient = Sasl.createSaslClient(new String[]{ mechanism },null, "AMQP", "localhost", null,
- SecurityHelper.createCallbackHandler(mechanism,_username,_password ));
- response = saslClient.evaluateChallenge(new byte[0]);
- }
- catch (UnsupportedEncodingException e)
- {
- // need error handling
- }
- catch (SaslException e)
- {
- // need error handling
- }
- catch (QpidException e)
- {
- // need error handling
- }
-
- Map<String,Object> props = new HashMap<String,Object>();
- context.connectionStartOk(props, mechanism, response, _locale);
+ conn.exception(new ConnectionException(error.getMessage()));
}
- @Override public void connectionSecure(Channel context, ConnectionSecure struct)
+ public void handle(Connection conn, Method method)
{
- try
- {
- byte[] response = saslClient.evaluateChallenge(struct.getChallenge());
- context.connectionSecureOk(response);
- }
- catch (SaslException e)
- {
- // need error handling
- }
+ conn.dispatch(method);
}
- @Override public void connectionTune(Channel context, ConnectionTune struct)
+ @Override public void connectionHeartbeat(Connection conn, ConnectionHeartbeat hearbeat)
{
- context.getConnection().setChannelMax(struct.getChannelMax());
- context.connectionTuneOk(struct.getChannelMax(), struct.getMaxFrameSize(), struct.getHeartbeatMax());
- context.connectionOpen(_virtualHost, null, Option.INSIST);
+ // do nothing
}
-
- @Override public void connectionOpenOk(Channel context, ConnectionOpenOk struct)
+ @Override public void connectionClose(Connection conn, ConnectionClose close)
{
- List<Object> knownHosts = struct.getKnownHosts();
- if(_negotiationCompleteLock != null)
- {
- _negotiationCompleteLock.lock();
- try
- {
- _negotiationComplete.signalAll();
- }
- finally
- {
- _negotiationCompleteLock.unlock();
- }
- }
+ conn.connectionCloseOk();
+ conn.getSender().close();
+ conn.closeCode(close);
+ conn.setState(CLOSE_RCVD);
}
- public void connectionRedirect(Channel context, ConnectionRedirect struct)
+ @Override public void connectionCloseOk(Connection conn, ConnectionCloseOk ok)
{
- // not going to bother at the moment
+ conn.getSender().close();
}
- // ----------------------------------------------
- // Server side
- //-----------------------------------------------
- @Override public void connectionStartOk(Channel context, ConnectionStartOk struct)
+ @Override public void sessionDetach(Connection conn, SessionDetach dtc)
{
- //set the client side locale on the server side
- _locale = struct.getLocale();
- _mechanism = struct.getMechanism();
-
- //try
- //{
- //saslServer = Sasl.createSaslServer(_mechanism, "AMQP", "ABC",null,SecurityHelper.createCallbackHandler(_mechanism,_username,_password));
- //byte[] challenge = saslServer.evaluateResponse(struct.getResponse().getBytes());
- byte[] challenge = null;
- if ( challenge == null)
- {
- context.connectionTune(Integer.MAX_VALUE, maxFrame, 0, Integer.MAX_VALUE);
- }
- else
- {
- try
- {
- context.connectionSecure(challenge);
- }
- catch(Exception e)
- {
-
- }
- }
-
-
- /*}
- catch (SaslException e)
- {
- // need error handling
- }
- catch (QpidException e)
- {
- // need error handling
- }*/
+ Session ssn = conn.getSession(dtc.getChannel());
+ conn.unmap(ssn);
+ ssn.sessionDetached(dtc.getName(), SessionDetachCode.NORMAL);
+ ssn.closed();
}
- @Override public void connectionSecureOk(Channel context, ConnectionSecureOk struct)
+ @Override public void sessionDetached(Connection conn, SessionDetached dtc)
{
- try
- {
- saslServer = Sasl.createSaslServer(_mechanism, "AMQP", "ABC",new HashMap(),SecurityHelper.createCallbackHandler(_mechanism,_username,_password));
- byte[] challenge = saslServer.evaluateResponse(struct.getResponse());
- if ( challenge == null)
- {
- context.connectionTune(Integer.MAX_VALUE, maxFrame, 0, Integer.MAX_VALUE);
- }
- else
- {
- try
- {
- context.connectionSecure(challenge);
- }
- catch(Exception e)
- {
-
- }
- }
-
-
- }
- catch (SaslException e)
+ Session ssn = conn.getSession(dtc.getChannel());
+ if (ssn != null)
{
- // need error handling
+ conn.unmap(ssn);
+ ssn.closed();
}
- catch (QpidException e)
- {
- // need error handling
- }
- }
-
-
- @Override public void connectionOpen(Channel context, ConnectionOpen struct)
- {
- List<Object> hosts = new ArrayList<Object>();
- hosts.add("amqp:1223243232325");
- context.connectionOpenOk(hosts);
- }
-
- @Override public void connectionClose(Channel ch, ConnectionClose close)
- {
- ch.getConnection().closeCode(close);
- ch.connectionCloseOk();
- }
-
- public String getPassword()
- {
- return _password;
- }
-
- public void setPassword(String password)
- {
- _password = password;
- }
-
- public String getUsername()
- {
- return _username;
- }
-
- public void setUsername(String username)
- {
- _username = username;
- }
-
- public String getVirtualHost()
- {
- return _virtualHost;
- }
-
- public void setVirtualHost(String host)
- {
- _virtualHost = host;
}
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/ConnectionException.java b/java/common/src/main/java/org/apache/qpid/transport/ConnectionException.java
index c3239ef684..6d3972eb43 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/ConnectionException.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/ConnectionException.java
@@ -26,20 +26,45 @@ package org.apache.qpid.transport;
*
*/
-public class ConnectionException extends RuntimeException
+public class ConnectionException extends TransportException
{
private ConnectionClose close;
- public ConnectionException(ConnectionClose close)
+ public ConnectionException(String message, ConnectionClose close, Throwable cause)
{
- super(close.getReplyText());
+ super(message, cause);
this.close = close;
}
+ public ConnectionException(String message)
+ {
+ this(message, null, null);
+ }
+
+ public ConnectionException(String message, Throwable cause)
+ {
+ this(message, null, cause);
+ }
+
+ public ConnectionException(Throwable cause)
+ {
+ this(cause.getMessage(), null, cause);
+ }
+
+ public ConnectionException(ConnectionClose close)
+ {
+ this(close.getReplyText(), close, null);
+ }
+
public ConnectionClose getClose()
{
return close;
}
+ @Override public void rethrow()
+ {
+ throw new ConnectionException(getMessage(), close, this);
+ }
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/ConnectionListener.java b/java/common/src/main/java/org/apache/qpid/transport/ConnectionListener.java
new file mode 100644
index 0000000000..616e76825a
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/ConnectionListener.java
@@ -0,0 +1,38 @@
+/*
+ *
+ * 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;
+
+
+/**
+ * ConnectionListener
+ *
+ */
+
+public interface ConnectionListener
+{
+
+ void opened(Connection connection);
+
+ void exception(Connection connection, ConnectionException exception);
+
+ void closed(Connection connection);
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/Echo.java b/java/common/src/main/java/org/apache/qpid/transport/Echo.java
index b2be32331a..0e969464ab 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/Echo.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/Echo.java
@@ -32,36 +32,41 @@ import org.apache.qpid.transport.network.io.IoAcceptor;
*
*/
-public class Echo extends SessionDelegate
+public class Echo implements SessionListener
{
- public void messageTransfer(Session ssn, MessageTransfer xfr)
+ public void opened(Session ssn) {}
+
+ public void resumed(Session ssn) {}
+
+ public void message(Session ssn, MessageTransfer xfr)
{
+ int id = xfr.getId();
ssn.invoke(xfr);
- ssn.processed(xfr);
+ ssn.processed(id);
+ }
+
+ public void exception(Session ssn, SessionException exc)
+ {
+ exc.printStackTrace();
}
+ public void closed(Session ssn) {}
+
public static final void main(String[] args) throws IOException
{
- ConnectionDelegate delegate = new ConnectionDelegate()
+ ConnectionDelegate delegate = new ServerDelegate()
{
- public SessionDelegate getSessionDelegate()
- {
- return new Echo();
- }
- public void exception(Throwable t)
+ @Override public Session getSession(Connection conn, SessionAttach atc)
{
- t.printStackTrace();
+ Session ssn = super.getSession(conn, atc);
+ ssn.setSessionListener(new Echo());
+ return ssn;
}
- public void closed() {}
};
- //hack
- delegate.setUsername("guest");
- delegate.setPassword("guest");
-
IoAcceptor ioa = new IoAcceptor
- ("0.0.0.0", 5672, new ConnectionBinding(delegate));
+ ("0.0.0.0", 5672, ConnectionBinding.get(delegate));
ioa.start();
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/Method.java b/java/common/src/main/java/org/apache/qpid/transport/Method.java
index 37c347db98..3c80180d0b 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/Method.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/Method.java
@@ -35,6 +35,7 @@ import static org.apache.qpid.transport.util.Functions.*;
public abstract class Method extends Struct implements ProtocolEvent
{
+
public static final Method create(int type)
{
// XXX: should generate separate factories for separate
@@ -43,11 +44,18 @@ public abstract class Method extends Struct implements ProtocolEvent
}
// XXX: command subclass?
+ public static interface CompletionListener
+ {
+ public void onComplete(Method method);
+ }
+
private int id;
private int channel;
private boolean idSet = false;
private boolean sync = false;
private boolean batch = false;
+ private boolean unreliable = false;
+ private CompletionListener completionListener;
public final int getId()
{
@@ -60,6 +68,11 @@ public abstract class Method extends Struct implements ProtocolEvent
this.idSet = true;
}
+ boolean idSet()
+ {
+ return idSet;
+ }
+
public final int getChannel()
{
return channel;
@@ -75,7 +88,7 @@ public abstract class Method extends Struct implements ProtocolEvent
return sync;
}
- protected final void setSync(boolean value)
+ public final void setSync(boolean value)
{
this.sync = value;
}
@@ -85,12 +98,22 @@ public abstract class Method extends Struct implements ProtocolEvent
return batch;
}
- protected final void setBatch(boolean value)
+ final void setBatch(boolean value)
{
this.batch = value;
}
- public abstract boolean hasPayloadSegment();
+ public final boolean isUnreliable()
+ {
+ return unreliable;
+ }
+
+ final void setUnreliable(boolean value)
+ {
+ this.unreliable = value;
+ }
+
+ public abstract boolean hasPayload();
public Header getHeader()
{
@@ -112,18 +135,22 @@ public abstract class Method extends Struct implements ProtocolEvent
throw new UnsupportedOperationException();
}
- public abstract byte getEncodedTrack();
-
- public <C> void dispatch(C context, MethodDelegate<C> delegate)
+ public int getBodySize()
{
- throw new UnsupportedOperationException();
+ ByteBuffer body = getBody();
+ if (body == null)
+ {
+ return 0;
+ }
+ else
+ {
+ return body.remaining();
+ }
}
- public <C> void dispatch
- (C context, org.apache.qpid.transport.v1_0.MethodDelegate<C> delegate)
- {
- throw new UnsupportedOperationException();
- }
+ public abstract byte getEncodedTrack();
+
+ public abstract <C> void dispatch(C context, MethodDelegate<C> delegate);
public <C> void delegate(C context, ProtocolDelegate<C> delegate)
{
@@ -137,6 +164,26 @@ public abstract class Method extends Struct implements ProtocolEvent
}
}
+
+ public void setCompletionListener(CompletionListener completionListener)
+ {
+ this.completionListener = completionListener;
+ }
+
+ public void complete()
+ {
+ if(completionListener!= null)
+ {
+ completionListener.onComplete(this);
+ completionListener = null;
+ }
+ }
+
+ public boolean hasCompletionListener()
+ {
+ return completionListener != null;
+ }
+
public String toString()
{
StringBuilder str = new StringBuilder();
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/NetworkDriverConfiguration.java b/java/common/src/main/java/org/apache/qpid/transport/NetworkDriverConfiguration.java
new file mode 100644
index 0000000000..c38afe5dd5
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/NetworkDriverConfiguration.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * 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;
+
+/**
+ * This interface provides a means for NetworkDrivers to configure TCP options such as incoming and outgoing
+ * 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 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();
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/OpenException.java b/java/common/src/main/java/org/apache/qpid/transport/OpenException.java
new file mode 100644
index 0000000000..68fbb5e8ec
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/OpenException.java
@@ -0,0 +1,34 @@
+/*
+ *
+ * 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.io.IOException;
+
+public class OpenException extends IOException
+{
+
+ public OpenException(String string, Throwable lastException)
+ {
+ super(string, lastException);
+ }
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/ProtocolHeader.java b/java/common/src/main/java/org/apache/qpid/transport/ProtocolHeader.java
index fa0c1e9c63..00ea55ff96 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/ProtocolHeader.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/ProtocolHeader.java
@@ -39,13 +39,15 @@ public final class ProtocolHeader implements NetworkEvent, ProtocolEvent
private static final byte[] AMQP = {'A', 'M', 'Q', 'P' };
private static final byte CLASS = 1;
+ final private byte protoClass;
final private byte instance;
final private byte major;
final private byte minor;
private int channel;
- public ProtocolHeader(byte instance, byte major, byte minor)
+ public ProtocolHeader(byte protoClass, byte instance, byte major, byte minor)
{
+ this.protoClass = protoClass;
this.instance = instance;
this.major = major;
this.minor = minor;
@@ -53,7 +55,7 @@ public final class ProtocolHeader implements NetworkEvent, ProtocolEvent
public ProtocolHeader(int instance, int major, int minor)
{
- this((byte) instance, (byte) major, (byte) minor);
+ this(CLASS, (byte) instance, (byte) major, (byte) minor);
}
public byte getInstance()
@@ -90,7 +92,7 @@ public final class ProtocolHeader implements NetworkEvent, ProtocolEvent
{
ByteBuffer buf = ByteBuffer.allocate(8);
buf.put(AMQP);
- buf.put(CLASS);
+ buf.put(protoClass);
buf.put(instance);
buf.put(major);
buf.put(minor);
diff --git a/java/common/src/main/java/org/apache/qpid/transport/ProtocolVersionException.java b/java/common/src/main/java/org/apache/qpid/transport/ProtocolVersionException.java
index 2de0c169a5..db8064268c 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/ProtocolVersionException.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/ProtocolVersionException.java
@@ -26,19 +26,24 @@ package org.apache.qpid.transport;
*
*/
-public final class ProtocolVersionException extends TransportException
+public final class ProtocolVersionException extends ConnectionException
{
private final byte major;
private final byte minor;
- public ProtocolVersionException(byte major, byte minor)
+ public ProtocolVersionException(byte major, byte minor, Throwable cause)
{
- super(String.format("version missmatch: %s-%s", major, minor));
+ super(String.format("version mismatch: %s-%s", major, minor), cause);
this.major = major;
this.minor = minor;
}
+ public ProtocolVersionException(byte major, byte minor)
+ {
+ this(major, minor, null);
+ }
+
public byte getMajor()
{
return this.major;
@@ -49,4 +54,9 @@ public final class ProtocolVersionException extends TransportException
return this.minor;
}
+ @Override public void rethrow()
+ {
+ throw new ProtocolVersionException(major, minor, this);
+ }
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/ProtocolViolationException.java b/java/common/src/main/java/org/apache/qpid/transport/ProtocolViolationException.java
new file mode 100644
index 0000000000..6787157e8e
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/ProtocolViolationException.java
@@ -0,0 +1,35 @@
+/*
+ *
+ * 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;
+
+
+/**
+ * ProtocolViolationException
+ *
+ */
+
+public final class ProtocolViolationException extends ConnectionException
+{
+ public ProtocolViolationException(String msg,Throwable cause)
+ {
+ super(msg, cause);
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/RangeSet.java b/java/common/src/main/java/org/apache/qpid/transport/RangeSet.java
index 9b2744ee8b..3850dc162b 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/RangeSet.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/RangeSet.java
@@ -52,6 +52,11 @@ public final class RangeSet implements Iterable<Range>
return ranges.getFirst();
}
+ public Range getLast()
+ {
+ return ranges.getLast();
+ }
+
public boolean includes(Range range)
{
for (Range r : this)
diff --git a/java/common/src/main/java/org/apache/qpid/transport/Sender.java b/java/common/src/main/java/org/apache/qpid/transport/Sender.java
index 9a6f675d7f..475289c83f 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/Sender.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/Sender.java
@@ -28,6 +28,7 @@ package org.apache.qpid.transport;
public interface Sender<T>
{
+ void setIdleTimeout(long l);
void send(T msg);
diff --git a/java/common/src/main/java/org/apache/qpid/transport/ChannelDelegate.java b/java/common/src/main/java/org/apache/qpid/transport/SenderException.java
index 8475fbf174..a96079dc27 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/ChannelDelegate.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/SenderException.java
@@ -20,35 +20,33 @@
*/
package org.apache.qpid.transport;
-import java.util.UUID;
-
/**
- * ChannelDelegate
+ * SenderException
*
- * @author Rafael H. Schloming
*/
-class ChannelDelegate extends MethodDelegate<Channel>
+public class SenderException extends TransportException
{
- public @Override void sessionAttach(Channel channel, SessionAttach atch)
+ public SenderException(String message, Throwable cause)
+ {
+ super(message, cause);
+ }
+
+ public SenderException(String message)
{
- Session ssn = new Session(atch.getName());
- ssn.attach(channel);
- ssn.sessionAttached(ssn.getName());
+ super(message);
}
- public @Override void sessionDetached(Channel channel, SessionDetached closed)
+ public SenderException(Throwable cause)
{
- channel.closed();
+ super(cause);
}
- public @Override void sessionDetach(Channel channel, SessionDetach dtc)
+ public void rethrow()
{
- channel.getSession().closed();
- channel.sessionDetached(dtc.getName(), SessionDetachCode.NORMAL);
- channel.closed();
+ throw new SenderException(getMessage(), this);
}
}
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
new file mode 100644
index 0000000000..453921ea2b
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/ServerDelegate.java
@@ -0,0 +1,183 @@
+/*
+ *
+ * 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.util.Collections;
+
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.Lock;
+
+import java.io.UnsupportedEncodingException;
+
+import org.apache.qpid.QpidException;
+
+import javax.security.sasl.Sasl;
+import javax.security.sasl.SaslClient;
+import javax.security.sasl.SaslException;
+import javax.security.sasl.SaslServer;
+
+
+import static org.apache.qpid.transport.Connection.State.*;
+
+
+/**
+ * ServerDelegate
+ *
+ */
+
+public class ServerDelegate extends ConnectionDelegate
+{
+
+ private SaslServer saslServer;
+ private List<Object> _locales;
+ private List<Object> _mechanisms;
+ private Map<String, Object> _clientProperties;
+
+
+ public ServerDelegate()
+ {
+ this(null, Collections.EMPTY_LIST, Collections.singletonList((Object)"utf8"));
+ }
+
+ protected ServerDelegate(Map<String, Object> clientProperties, List<Object> mechanisms, List<Object> locales)
+ {
+ _clientProperties = clientProperties;
+ _mechanisms = mechanisms;
+ _locales = locales;
+ }
+
+ public void init(Connection conn, ProtocolHeader hdr)
+ {
+ conn.send(new ProtocolHeader(1, 0, 10));
+
+ conn.connectionStart(_clientProperties, _mechanisms, _locales);
+ }
+
+ @Override public void connectionStartOk(Connection conn, ConnectionStartOk ok)
+ {
+ conn.setLocale(ok.getLocale());
+ String mechanism = ok.getMechanism();
+
+ if (mechanism == null || mechanism.length() == 0)
+ {
+ conn.connectionTune
+ (Integer.MAX_VALUE,
+ org.apache.qpid.transport.network.ConnectionBinding.MAX_FRAME_SIZE,
+ 0, Integer.MAX_VALUE);
+ return;
+ }
+
+ try
+ {
+
+ SaslServer ss = createSaslServer(mechanism);
+ if (ss == null)
+ {
+ conn.connectionClose
+ (ConnectionCloseCode.CONNECTION_FORCED,
+ "null SASL mechanism: " + mechanism);
+ return;
+ }
+ conn.setSaslServer(ss);
+ secure(conn, ok.getResponse());
+ }
+ catch (SaslException e)
+ {
+ conn.exception(e);
+ }
+ }
+
+ protected SaslServer createSaslServer(String mechanism)
+ throws SaslException
+ {
+ SaslServer ss = Sasl.createSaslServer
+ (mechanism, "AMQP", "localhost", null, null);
+ return ss;
+ }
+
+ private void secure(Connection conn, byte[] response)
+ {
+ SaslServer ss = conn.getSaslServer();
+ try
+ {
+ byte[] challenge = ss.evaluateResponse(response);
+ if (ss.isComplete())
+ {
+ ss.dispose();
+ conn.connectionTune
+ (Integer.MAX_VALUE,
+ org.apache.qpid.transport.network.ConnectionBinding.MAX_FRAME_SIZE,
+ 0, Integer.MAX_VALUE);
+ conn.setAuthorizationID(ss.getAuthorizationID());
+ }
+ else
+ {
+ conn.connectionSecure(challenge);
+ }
+ }
+ catch (SaslException e)
+ {
+ conn.exception(e);
+ }
+ }
+
+ @Override public void connectionSecureOk(Connection conn, ConnectionSecureOk ok)
+ {
+ secure(conn, ok.getResponse());
+ }
+
+ @Override public void connectionTuneOk(Connection conn, ConnectionTuneOk ok)
+ {
+
+ }
+
+ @Override public void connectionOpen(Connection conn, ConnectionOpen open)
+ {
+ conn.connectionOpenOk(Collections.EMPTY_LIST);
+
+ conn.setState(OPEN);
+ }
+
+ protected Session getSession(Connection conn, SessionDelegate delegate, SessionAttach atc)
+ {
+ return new Session(conn, delegate, new Binary(atc.getName()), 0);
+ }
+
+
+ public Session getSession(Connection conn, SessionAttach atc)
+ {
+ return new Session(conn, new Binary(atc.getName()), 0);
+ }
+
+ @Override public void sessionAttach(Connection conn, SessionAttach atc)
+ {
+ Session ssn = getSession(conn, atc);
+ conn.map(ssn, atc.getChannel());
+ ssn.sessionAttached(atc.getName());
+ ssn.setState(Session.State.OPEN);
+ }
+
+}
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 10ca6cfb0a..818bb19c08 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
@@ -24,6 +24,7 @@ package org.apache.qpid.transport;
import org.apache.qpid.transport.network.Frame;
import org.apache.qpid.transport.util.Logger;
+import org.apache.qpid.transport.util.Waiter;
import java.nio.ByteBuffer;
import java.util.ArrayList;
@@ -32,8 +33,11 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
import static org.apache.qpid.transport.Option.*;
+import static org.apache.qpid.transport.Session.State.*;
import static org.apache.qpid.transport.util.Functions.*;
import static org.apache.qpid.util.Serial.*;
import static org.apache.qpid.util.Strings.*;
@@ -44,59 +48,125 @@ import static org.apache.qpid.util.Strings.*;
* @author Rafael H. Schloming
*/
-public class Session extends Invoker
+public class Session extends SessionInvoker
{
private static final Logger log = Logger.get(Session.class);
- private static boolean ENABLE_REPLAY = false;
+ enum State { NEW, DETACHED, RESUMING, OPEN, CLOSING, CLOSED }
- static
+ class DefaultSessionListener implements SessionListener
{
- String enableReplay = "enable_command_replay";
- try
+
+ public void opened(Session ssn) {}
+
+ public void resumed(Session ssn) {}
+
+ public void message(Session ssn, MessageTransfer xfr)
{
- ENABLE_REPLAY = new Boolean(System.getProperties().getProperty(enableReplay, "false"));
+ log.info("message: %s", xfr);
}
- catch (Exception e)
+
+ public void exception(Session ssn, SessionException exc)
{
- ENABLE_REPLAY = false;
+ log.error(exc, "session exception");
}
+
+ public void closed(Session ssn) {}
}
- private byte[] name;
+ public static final int UNLIMITED_CREDIT = 0xFFFFFFFF;
+
+ private Connection connection;
+ private Binary name;
+ private long expiry;
+ private int channel;
+ private SessionDelegate delegate;
+ private SessionListener listener = new DefaultSessionListener();
private long timeout = 60000;
private boolean autoSync = false;
- // channel may be null
- Channel channel;
-
+ private boolean incomingInit;
// incoming command count
- int commandsIn = 0;
+ private int commandsIn;
// completed incoming commands
private final Object processedLock = new Object();
- private RangeSet processed = new RangeSet();
- private int maxProcessed = commandsIn - 1;
- private int syncPoint = maxProcessed;
+ private RangeSet processed;
+ private int maxProcessed;
+ private int syncPoint;
// outgoing command count
private int commandsOut = 0;
- private Map<Integer,Method> commands = new HashMap<Integer,Method>();
+ private Method[] commands = new Method[Integer.getInteger("qpid.session.command_limit", 64*1024)];
+ private int commandBytes = 0;
+ private int byteLimit = Integer.getInteger("qpid.session.byte_limit", 1024*1024);
private int maxComplete = commandsOut - 1;
private boolean needSync = false;
- private AtomicBoolean closed = new AtomicBoolean(false);
+ private State state = NEW;
+
+ // transfer flow control
+ private volatile boolean flowControl = false;
+ private Semaphore credit = new Semaphore(0);
+
+ private Thread resumer = null;
- public Session(byte[] name)
+ protected Session(Connection connection, Binary name, long expiry)
{
+ this(connection, new SessionDelegate(), name, expiry);
+ }
+
+ protected Session(Connection connection, SessionDelegate delegate, Binary name, long expiry)
+ {
+ this.connection = connection;
+ this.delegate = delegate;
this.name = name;
+ this.expiry = expiry;
+ initReceiver();
+ }
+
+ public Connection getConnection()
+ {
+ return connection;
}
- public byte[] getName()
+ public Binary getName()
{
return name;
}
+ void setExpiry(long expiry)
+ {
+ this.expiry = expiry;
+ }
+
+ int getChannel()
+ {
+ return channel;
+ }
+
+ void setChannel(int channel)
+ {
+ this.channel = channel;
+ }
+
+ public void setSessionListener(SessionListener listener)
+ {
+ if (listener == null)
+ {
+ this.listener = new DefaultSessionListener();
+ }
+ else
+ {
+ this.listener = listener;
+ }
+ }
+
+ public SessionListener getSessionListener()
+ {
+ return listener;
+ }
+
public void setAutoSync(boolean value)
{
synchronized (commands)
@@ -105,9 +175,119 @@ public class Session extends Invoker
}
}
- public Map<Integer,Method> getOutstandingCommands()
+ void setState(State state)
+ {
+ synchronized (commands)
+ {
+ this.state = state;
+ commands.notifyAll();
+ }
+ }
+
+ void setFlowControl(boolean value)
+ {
+ flowControl = value;
+ }
+
+ void addCredit(int value)
+ {
+ credit.release(value);
+ }
+
+ void drainCredit()
{
- return commands;
+ credit.drainPermits();
+ }
+
+ void acquireCredit()
+ {
+ if (flowControl)
+ {
+ try
+ {
+ if (!credit.tryAcquire(timeout, TimeUnit.MILLISECONDS))
+ {
+ throw new SessionException
+ ("timed out waiting for message credit");
+ }
+ }
+ catch (InterruptedException e)
+ {
+ throw new SessionException
+ ("interrupted while waiting for credit", null, e);
+ }
+ }
+ }
+
+ private void initReceiver()
+ {
+ synchronized (processedLock)
+ {
+ incomingInit = false;
+ processed = new RangeSet();
+ }
+ }
+
+ void attach()
+ {
+ initReceiver();
+ sessionAttach(name.getBytes());
+ // XXX: when the broker and client support full session
+ // recovery we should use expiry as the requested timeout
+ sessionRequestTimeout(0);
+ }
+
+ void resume()
+ {
+ synchronized (commands)
+ {
+ for (int i = maxComplete + 1; lt(i, commandsOut); i++)
+ {
+ Method m = commands[mod(i, commands.length)];
+ if (m == null)
+ {
+ m = new ExecutionSync();
+ m.setId(i);
+ }
+ sessionCommandPoint(m.getId(), 0);
+ send(m);
+ }
+
+ sessionCommandPoint(commandsOut, 0);
+ sessionFlush(COMPLETED);
+ resumer = Thread.currentThread();
+ state = RESUMING;
+ listener.resumed(this);
+ resumer = null;
+ }
+ }
+
+ void dump()
+ {
+ synchronized (commands)
+ {
+ for (Method m : commands)
+ {
+ if (m != null)
+ {
+ System.out.println(m);
+ }
+ }
+ }
+ }
+
+ final void commandPoint(int id)
+ {
+ synchronized (processedLock)
+ {
+ this.commandsIn = id;
+ if (!incomingInit)
+ {
+ incomingInit = true;
+ maxProcessed = commandsIn - 1;
+ syncPoint = maxProcessed;
+ }
+ }
}
public int getCommandsOut()
@@ -127,6 +307,11 @@ public class Session extends Invoker
final void identify(Method cmd)
{
+ if (!incomingInit)
+ {
+ throw new IllegalStateException();
+ }
+
int id = nextCommandId();
cmd.setId(id);
@@ -160,11 +345,19 @@ public class Session extends Invoker
public void processed(Range range)
{
- log.debug("%s processed(%s)", this, range);
+ log.debug("%s processed(%s) %s %s", this, range, syncPoint, maxProcessed);
boolean flush;
synchronized (processedLock)
{
+ log.debug("%s", processed);
+
+ if (ge(range.getUpper(), commandsIn))
+ {
+ throw new IllegalArgumentException
+ ("range exceeds max received command-id: " + range);
+ }
+
processed.add(range);
Range first = processed.getFirst();
int lower = first.getLower();
@@ -174,8 +367,12 @@ public class Session extends Invoker
{
maxProcessed = max(maxProcessed, upper);
}
- flush = lt(old, syncPoint) && ge(maxProcessed, syncPoint);
- syncPoint = maxProcessed;
+ boolean synced = ge(maxProcessed, syncPoint);
+ flush = lt(old, syncPoint) && synced;
+ if (synced)
+ {
+ syncPoint = maxProcessed;
+ }
}
if (flush)
{
@@ -183,6 +380,19 @@ public class Session extends Invoker
}
}
+ void flushExpected()
+ {
+ RangeSet rs = new RangeSet();
+ synchronized (processedLock)
+ {
+ if (incomingInit)
+ {
+ rs.add(commandsIn);
+ }
+ }
+ sessionExpected(rs, null);
+ }
+
public void flushProcessed(Option ... options)
{
RangeSet copy;
@@ -190,7 +400,15 @@ public class Session extends Invoker
{
copy = processed.copy();
}
- sessionCompleted(copy, options);
+
+ synchronized (commands)
+ {
+ if (state == DETACHED || state == CLOSING)
+ {
+ return;
+ }
+ sessionCompleted(copy, options);
+ }
}
void knownComplete(RangeSet kc)
@@ -228,21 +446,7 @@ public class Session extends Invoker
}
}
- public void attach(Channel channel)
- {
- this.channel = channel;
- channel.setSession(this);
- }
-
- public Method getCommand(int id)
- {
- synchronized (commands)
- {
- return commands.get(id);
- }
- }
-
- boolean complete(int lower, int upper)
+ protected boolean complete(int lower, int upper)
{
//avoid autoboxing
if(log.isDebugEnabled())
@@ -254,57 +458,210 @@ public class Session extends Invoker
int old = maxComplete;
for (int id = max(maxComplete, lower); le(id, upper); id++)
{
- commands.remove(id);
+ int idx = mod(id, commands.length);
+ Method m = commands[idx];
+ if (m != null)
+ {
+ commandBytes -= m.getBodySize();
+ m.complete();
+ commands[idx] = null;
+ }
}
if (le(lower, maxComplete + 1))
{
maxComplete = max(maxComplete, upper);
}
- log.debug("%s commands remaining: %s", this, commands);
+ log.debug("%s commands remaining: %s", this, commandsOut - maxComplete);
commands.notifyAll();
return gt(maxComplete, old);
}
}
- public void invoke(Method m)
+ void received(Method m)
{
- if (closed.get())
+ m.delegate(this, delegate);
+ }
+
+ private void send(Method m)
+ {
+ m.setChannel(channel);
+ connection.send(m);
+
+ if (!m.isBatch())
{
- List<ExecutionException> exc = getExceptions();
- if (!exc.isEmpty())
- {
- throw new SessionException(exc);
- }
- else if (close != null)
- {
- throw new ConnectionException(close);
- }
- else
- {
- throw new SessionClosedException();
- }
+ connection.flush();
}
+ }
+
+ protected boolean isFull(int id)
+ {
+ return isCommandsFull(id) || isBytesFull();
+ }
+
+ protected boolean isBytesFull()
+ {
+ return commandBytes >= byteLimit;
+ }
+
+ protected boolean isCommandsFull(int id)
+ {
+ return id - maxComplete >= commands.length;
+ }
+
+ public void invoke(Method m)
+ {
+ invoke(m,(Runnable)null);
+ }
+ public void invoke(Method m, Runnable postIdSettingAction)
+ {
if (m.getEncodedTrack() == Frame.L4)
{
+ if (m.hasPayload())
+ {
+ acquireCredit();
+ }
+
synchronized (commands)
{
- int next = commandsOut++;
+ if (state == DETACHED && m.isUnreliable())
+ {
+ Thread current = Thread.currentThread();
+ if (!current.equals(resumer))
+ {
+ return;
+ }
+ }
+
+ if (state != OPEN && state != CLOSED)
+ {
+ Thread current = Thread.currentThread();
+ if (!current.equals(resumer))
+ {
+ Waiter w = new Waiter(commands, timeout);
+ while (w.hasTime() && (state != OPEN && state != CLOSED))
+ {
+ w.await();
+ }
+ }
+ }
+
+ switch (state)
+ {
+ case OPEN:
+ break;
+ case RESUMING:
+ Thread current = Thread.currentThread();
+ if (!current.equals(resumer))
+ {
+ throw new SessionException
+ ("timed out waiting for resume to finish");
+ }
+ break;
+ case CLOSED:
+ ExecutionException exc = getException();
+ if (exc != null)
+ {
+ throw new SessionException(exc);
+ }
+ else
+ {
+ throw new SessionClosedException();
+ }
+ default:
+ throw new SessionException
+ (String.format
+ ("timed out waiting for session to become open " +
+ "(state=%s)", state));
+ }
+
+ int next;
+ next = commandsOut++;
m.setId(next);
+ if(postIdSettingAction != null)
+ {
+ postIdSettingAction.run();
+ }
+
+ if (isFull(next))
+ {
+ Waiter w = new Waiter(commands, timeout);
+ while (w.hasTime() && isFull(next) && state != CLOSED)
+ {
+ if (state == OPEN || state == RESUMING)
+ {
+ try
+ {
+ sessionFlush(COMPLETED);
+ }
+ catch (SenderException e)
+ {
+ if (expiry > 0)
+ {
+ // if expiry is > 0 then this will
+ // happen again on resume
+ log.error(e, "error sending flush (full replay buffer)");
+ }
+ else
+ {
+ e.rethrow();
+ }
+ }
+ }
+ w.await();
+ }
+ }
+
+ if (state == CLOSED)
+ {
+ ExecutionException exc = getException();
+ if (exc != null)
+ {
+ throw new SessionException(exc);
+ }
+ else
+ {
+ throw new SessionClosedException();
+ }
+ }
+
+ if (isFull(next))
+ {
+ throw new SessionException("timed out waiting for completion");
+ }
+
if (next == 0)
{
sessionCommandPoint(0, 0);
}
- if (ENABLE_REPLAY)
+ if ((expiry > 0 && !m.isUnreliable()) || m.hasCompletionListener())
{
- commands.put(next, m);
+ commands[mod(next, commands.length)] = m;
+ commandBytes += m.getBodySize();
}
if (autoSync)
{
m.setSync(true);
}
needSync = !m.isSync();
- channel.method(m);
+
+ try
+ {
+ send(m);
+ }
+ catch (SenderException e)
+ {
+ if (expiry > 0)
+ {
+ // if expiry is > 0 then this will happen
+ // again on resume
+ log.error(e, "error sending command");
+ }
+ else
+ {
+ e.rethrow();
+ }
+ }
if (autoSync)
{
sync();
@@ -312,18 +669,39 @@ public class Session extends Invoker
// flush every 64K commands to avoid ambiguity on
// wraparound
- if ((next % 65536) == 0)
+ if (shouldIssueFlush(next))
{
- sessionFlush(COMPLETED);
+ try
+ {
+ sessionFlush(COMPLETED);
+ }
+ catch (SenderException e)
+ {
+ if (expiry > 0)
+ {
+ // if expiry is > 0 then this will happen
+ // again on resume
+ log.error(e, "error sending flush (periodic)");
+ }
+ else
+ {
+ e.rethrow();
+ }
+ }
}
}
}
else
{
- channel.method(m);
+ send(m);
}
}
+ protected boolean shouldIssueFlush(int next)
+ {
+ return (next % 65536) == 0;
+ }
+
public void sync()
{
sync(timeout);
@@ -341,31 +719,23 @@ public class Session extends Invoker
executionSync(SYNC);
}
- long start = System.currentTimeMillis();
- long elapsed = 0;
- while (!closed.get() && elapsed < timeout && lt(maxComplete, point))
+ Waiter w = new Waiter(commands, timeout);
+ while (w.hasTime() && state != CLOSED && lt(maxComplete, point))
{
- try {
- log.debug("%s waiting for[%d]: %d, %s", this, point,
- maxComplete, commands);
- commands.wait(timeout - elapsed);
- elapsed = System.currentTimeMillis() - start;
- }
- catch (InterruptedException e)
- {
- throw new RuntimeException(e);
- }
+ log.debug("%s waiting for[%d]: %d, %s", this, point,
+ maxComplete, commands);
+ w.await();
}
if (lt(maxComplete, point))
{
- if (closed.get())
+ if (state == CLOSED)
{
- throw new SessionException(getExceptions());
+ throw new SessionException(getException());
}
else
{
- throw new RuntimeException
+ throw new SessionException
(String.format
("timed out waiting for sync: complete = %s, point = %s", maxComplete, point));
}
@@ -375,8 +745,7 @@ public class Session extends Invoker
private Map<Integer,ResultFuture<?>> results =
new HashMap<Integer,ResultFuture<?>>();
- private List<ExecutionException> exceptions =
- new ArrayList<ExecutionException>();
+ private ExecutionException exception = null;
void result(int command, Struct result)
{
@@ -388,11 +757,17 @@ public class Session extends Invoker
future.set(result);
}
- void addException(ExecutionException exc)
+ void setException(ExecutionException exc)
{
- synchronized (exceptions)
+ synchronized (results)
{
- exceptions.add(exc);
+ if (exception != null)
+ {
+ throw new IllegalStateException
+ (String.format
+ ("too many exceptions: %s, %s", exception, exc));
+ }
+ exception = exc;
}
}
@@ -403,11 +778,11 @@ public class Session extends Invoker
this.close = close;
}
- List<ExecutionException> getExceptions()
+ ExecutionException getException()
{
- synchronized (exceptions)
+ synchronized (results)
{
- return new ArrayList<ExecutionException>(exceptions);
+ return exception;
}
}
@@ -450,20 +825,11 @@ public class Session extends Invoker
{
synchronized (this)
{
- long start = System.currentTimeMillis();
- long elapsed = 0;
- while (!closed.get() && timeout - elapsed > 0 && !isDone())
+ Waiter w = new Waiter(this, timeout);
+ while (w.hasTime() && state != CLOSED && !isDone())
{
- try
- {
- log.debug("%s waiting for result: %s", Session.this, this);
- wait(timeout - elapsed);
- elapsed = System.currentTimeMillis() - start;
- }
- catch (InterruptedException e)
- {
- throw new RuntimeException(e);
- }
+ log.debug("%s waiting for result: %s", Session.this, this);
+ w.await();
}
}
@@ -471,13 +837,15 @@ public class Session extends Invoker
{
return result;
}
- else if (closed.get())
+ else if (state == CLOSED)
{
- throw new SessionException(getExceptions());
+ throw new SessionException(getException());
}
else
{
- return null;
+ throw new SessionException
+ (String.format("%s timed out waiting for result: %s",
+ Session.this, this));
}
}
@@ -520,25 +888,29 @@ public class Session extends Invoker
public void close()
{
- sessionRequestTimeout(0);
- sessionDetach(name);
synchronized (commands)
{
- long start = System.currentTimeMillis();
- long elapsed = 0;
- try
+ state = CLOSING;
+ // XXX: we manually set the expiry to zero here to
+ // simulate full session recovery in brokers that don't
+ // support it, we should remove this line when there is
+ // broker support for full session resume:
+ expiry = 0;
+ sessionRequestTimeout(0);
+ sessionDetach(name.getBytes());
+ Waiter w = new Waiter(commands, timeout);
+ while (w.hasTime() && state != CLOSED)
{
- while (!closed.get() && elapsed < timeout)
- {
- commands.wait(timeout - elapsed);
- elapsed = System.currentTimeMillis() - start;
- }
+ w.await();
}
- catch (InterruptedException e)
+
+ if (state != CLOSED)
{
- throw new RuntimeException(e);
+ throw new SessionException("close() timed out");
}
}
+
+ connection.removeSession(this);
}
public void exception(Throwable t)
@@ -548,28 +920,43 @@ public class Session extends Invoker
public void closed()
{
- closed.set(true);
synchronized (commands)
{
+ if (expiry == 0 || getException() != null)
+ {
+ state = CLOSED;
+ }
+ else
+ {
+ state = DETACHED;
+ }
+
commands.notifyAll();
- }
- synchronized (results)
- {
- for (ResultFuture<?> result : results.values())
+
+ synchronized (results)
{
- synchronized(result)
+ for (ResultFuture<?> result : results.values())
{
- result.notifyAll();
+ synchronized(result)
+ {
+ result.notifyAll();
+ }
}
}
+ if(state == CLOSED)
+ {
+ delegate.closed(this);
+ }
+ else
+ {
+ delegate.detached(this);
+ }
}
- channel.setSession(null);
- channel = null;
}
public String toString()
{
- return String.format("ssn:%s", str(name));
+ return String.format("ssn:%s", name);
}
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/SessionClosedException.java b/java/common/src/main/java/org/apache/qpid/transport/SessionClosedException.java
index d2c54cf339..64f9039484 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/SessionClosedException.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/SessionClosedException.java
@@ -33,7 +33,17 @@ public class SessionClosedException extends SessionException
public SessionClosedException()
{
- super(Collections.EMPTY_LIST);
+ this(null);
+ }
+
+ public SessionClosedException(Throwable cause)
+ {
+ super("session closed", null, cause);
+ }
+
+ @Override public void rethrow()
+ {
+ throw new SessionClosedException(this);
}
}
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 5e4336f988..6146f029b2 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
@@ -20,7 +20,7 @@
*/
package org.apache.qpid.transport;
-import org.apache.qpid.transport.network.Frame;
+import org.apache.qpid.transport.util.Logger;
/**
@@ -29,10 +29,12 @@ import org.apache.qpid.transport.network.Frame;
* @author Rafael H. Schloming
*/
-public abstract class SessionDelegate
+public class SessionDelegate
extends MethodDelegate<Session>
implements ProtocolDelegate<Session>
{
+ private static final Logger log = Logger.get(SessionDelegate.class);
+
public void init(Session ssn, ProtocolHeader hdr) { }
public void control(Session ssn, Method method) {
@@ -42,7 +44,7 @@ public abstract class SessionDelegate
public void command(Session ssn, Method method) {
ssn.identify(method);
method.dispatch(ssn, this);
- if (!method.hasPayloadSegment())
+ if (!method.hasPayload())
{
ssn.processed(method);
}
@@ -50,14 +52,21 @@ public abstract class SessionDelegate
public void error(Session ssn, ProtocolError error) { }
- @Override public void executionResult(Session ssn, ExecutionResult result)
+ public void handle(Session ssn, Method method)
{
- ssn.result(result.getCommandId(), result.getValue());
+ log.warn("UNHANDLED: [%s] %s", ssn, method);
}
- @Override public void executionException(Session ssn, ExecutionException exc)
+ @Override public void sessionAttached(Session ssn, SessionAttached atc)
{
- ssn.addException(exc);
+ ssn.setState(Session.State.OPEN);
+ }
+
+ @Override public void sessionTimeout(Session ssn, SessionTimeout t)
+ {
+ // XXX: we ignore this right now, we should uncomment this
+ // when full session resume is supported:
+ // ssn.setExpiry(t.getTimeout());
}
@Override public void sessionCompleted(Session ssn, SessionCompleted cmp)
@@ -108,13 +117,13 @@ public abstract class SessionDelegate
}
if (flush.getExpected())
{
- throw new Error("not implemented");
+ ssn.flushExpected();
}
}
@Override public void sessionCommandPoint(Session ssn, SessionCommandPoint scp)
{
- ssn.commandsIn = scp.getCommandId();
+ ssn.commandPoint(scp.getCommandId());
}
@Override public void executionSync(Session ssn, ExecutionSync sync)
@@ -122,4 +131,64 @@ public abstract class SessionDelegate
ssn.syncPoint();
}
+ @Override public void executionResult(Session ssn, ExecutionResult result)
+ {
+ ssn.result(result.getCommandId(), result.getValue());
+ }
+
+ @Override public void executionException(Session ssn, ExecutionException exc)
+ {
+ ssn.setException(exc);
+ }
+
+ @Override public void messageTransfer(Session ssn, MessageTransfer xfr)
+ {
+ ssn.getSessionListener().message(ssn, xfr);
+ }
+
+ @Override public void messageSetFlowMode(Session ssn, MessageSetFlowMode sfm)
+ {
+ if ("".equals(sfm.getDestination()) &&
+ MessageFlowMode.CREDIT.equals(sfm.getFlowMode()))
+ {
+ ssn.setFlowControl(true);
+ }
+ else
+ {
+ super.messageSetFlowMode(ssn, sfm);
+ }
+ }
+
+ @Override public void messageFlow(Session ssn, MessageFlow flow)
+ {
+ if ("".equals(flow.getDestination()) &&
+ MessageCreditUnit.MESSAGE.equals(flow.getUnit()))
+ {
+ ssn.addCredit((int) flow.getValue());
+ }
+ else
+ {
+ super.messageFlow(ssn, flow);
+ }
+ }
+
+ @Override public void messageStop(Session ssn, MessageStop stop)
+ {
+ if ("".equals(stop.getDestination()))
+ {
+ ssn.drainCredit();
+ }
+ else
+ {
+ super.messageStop(ssn, stop);
+ }
+ }
+
+ public void closed(Session session)
+ {
+ }
+
+ public void detached(Session session)
+ {
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/SessionException.java b/java/common/src/main/java/org/apache/qpid/transport/SessionException.java
index dc294b2206..c4fc9558a1 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/SessionException.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/SessionException.java
@@ -27,20 +27,35 @@ import java.util.List;
*
*/
-public class SessionException extends RuntimeException
+public class SessionException extends TransportException
{
- private List<ExecutionException> exceptions;
+ private ExecutionException exception;
- public SessionException(List<ExecutionException> exceptions)
+ public SessionException(String message, ExecutionException exception, Throwable cause)
{
- super(exceptions.isEmpty() ? "" : exceptions.toString());
- this.exceptions = exceptions;
+ super(message, cause);
+ this.exception = exception;
}
- public List<ExecutionException> getExceptions()
+ public SessionException(ExecutionException exception)
{
- return exceptions;
+ this(String.valueOf(exception), exception, null);
+ }
+
+ public SessionException(String message)
+ {
+ this(message, null, null);
+ }
+
+ public ExecutionException getException()
+ {
+ return exception;
+ }
+
+ @Override public void rethrow()
+ {
+ throw new SessionException(getMessage(), exception, this);
}
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/SessionListener.java b/java/common/src/main/java/org/apache/qpid/transport/SessionListener.java
new file mode 100644
index 0000000000..eb650eb9ed
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/SessionListener.java
@@ -0,0 +1,42 @@
+/*
+ *
+ * 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;
+
+
+/**
+ * SessionListener
+ *
+ */
+
+public interface SessionListener
+{
+
+ void opened(Session session);
+
+ void resumed(Session session);
+
+ void message(Session ssn, MessageTransfer xfr);
+
+ void exception(Session session, SessionException exception);
+
+ void closed(Session session);
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/Sink.java b/java/common/src/main/java/org/apache/qpid/transport/Sink.java
index 8653acedbe..88870284f6 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/Sink.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/Sink.java
@@ -31,7 +31,7 @@ import org.apache.qpid.transport.network.io.IoAcceptor;
*
*/
-public class Sink extends SessionDelegate
+public class Sink implements SessionListener
{
private static final String FORMAT_HDR = "%-12s %-18s %-18s %-18s";
@@ -85,7 +85,11 @@ public class Sink extends SessionDelegate
return String.format("%d/%.2f", count, ((double) bytes)/(1024*1024));
}
- public void messageTransfer(Session ssn, MessageTransfer xfr)
+ public void opened(Session ssn) {}
+
+ public void resumed(Session ssn) {}
+
+ public void message(Session ssn, MessageTransfer xfr)
{
count++;
bytes += xfr.getBody().remaining();
@@ -101,30 +105,27 @@ public class Sink extends SessionDelegate
ssn.processed(xfr);
}
- public static final void main(String[] args) throws IOException
+ public void exception(Session ssn, SessionException exc)
{
- ConnectionDelegate delegate = new ConnectionDelegate()
- {
+ exc.printStackTrace();
+ }
- public SessionDelegate getSessionDelegate()
- {
- return new Sink();
- }
+ public void closed(Session ssn) {}
- public void exception(Throwable t)
+ public static final void main(String[] args) throws IOException
+ {
+ ConnectionDelegate delegate = new ServerDelegate()
+ {
+ @Override public Session getSession(Connection conn, SessionAttach atc)
{
- t.printStackTrace();
+ Session ssn = super.getSession(conn, atc);
+ ssn.setSessionListener(new Sink());
+ return ssn;
}
-
- public void closed() {}
};
- //hack
- delegate.setUsername("guest");
- delegate.setPassword("guest");
-
IoAcceptor ioa = new IoAcceptor
- ("0.0.0.0", 5672, new ConnectionBinding(delegate));
+ ("0.0.0.0", 5672, ConnectionBinding.get(delegate));
System.out.println
(String.format
(FORMAT_HDR, "Session", "Count/MBytes", "Cumulative Rate", "Interval Rate"));
diff --git a/java/common/src/main/java/org/apache/qpid/transport/Struct.java b/java/common/src/main/java/org/apache/qpid/transport/Struct.java
index 097a6de1b5..22bd9f34ad 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/Struct.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/Struct.java
@@ -42,7 +42,7 @@ public abstract class Struct implements Encodable
return StructFactory.create(type);
}
- protected boolean dirty = true;
+ boolean dirty = true;
public boolean isDirty()
{
diff --git a/java/common/src/main/java/org/apache/qpid/transport/TransportException.java b/java/common/src/main/java/org/apache/qpid/transport/TransportException.java
index 5ef15154fc..0de190dfad 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/TransportException.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/TransportException.java
@@ -43,4 +43,9 @@ public class TransportException extends RuntimeException
super(cause);
}
+ public void rethrow()
+ {
+ throw new TransportException(getMessage(), this);
+ }
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/codec/BBDecoder.java b/java/common/src/main/java/org/apache/qpid/transport/codec/BBDecoder.java
index dd634eb94a..6f7a2fa3b2 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/codec/BBDecoder.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/codec/BBDecoder.java
@@ -25,16 +25,14 @@ import java.nio.ByteOrder;
import org.apache.qpid.transport.Binary;
-
/**
- * BBDecoder
+ * Byte Buffer Decoder.
+ * Decoder concrete implementor using a backing byte buffer for decoding data.
*
* @author Rafael H. Schloming
*/
-
public final class BBDecoder extends AbstractDecoder
{
-
private ByteBuffer in;
public void init(ByteBuffer in)
@@ -93,4 +91,54 @@ public final class BBDecoder extends AbstractDecoder
return in.getLong();
}
-}
+ public byte[] readBin128()
+ {
+ byte[] result = new byte[16];
+ get(result);
+ return result;
+ }
+
+ public byte[] readBytes(int howManyBytes)
+ {
+ byte[] result = new byte[howManyBytes];
+ get(result);
+ return result;
+ }
+
+ public double readDouble()
+ {
+ return in.getDouble();
+ }
+
+ public float readFloat()
+ {
+ return in.getFloat();
+ }
+
+ public short readInt16()
+ {
+ return in.getShort();
+ }
+
+ public int readInt32()
+ {
+ return in.getInt();
+ }
+
+ public byte readInt8()
+ {
+ return in.get();
+ }
+
+ public byte[] readReaminingBytes()
+ {
+ byte[] result = new byte[in.limit() - in.position()];
+ get(result);
+ return result;
+ }
+
+ public long readInt64()
+ {
+ return in.getLong();
+ }
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/transport/codec/BBEncoder.java b/java/common/src/main/java/org/apache/qpid/transport/codec/BBEncoder.java
index 390de881ab..d18a0f64db 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/codec/BBEncoder.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/codec/BBEncoder.java
@@ -26,14 +26,13 @@ import java.nio.ByteOrder;
/**
- * BBEncoder
- *
+ * Byte Buffer Encoder.
+ * Encoder concrete implementor using a backing byte buffer for encoding data.
+ *
* @author Rafael H. Schloming
*/
-
public final class BBEncoder extends AbstractEncoder
{
-
private ByteBuffer out;
private int segment;
@@ -60,12 +59,23 @@ public final class BBEncoder extends AbstractEncoder
return slice;
}
+ public ByteBuffer buffer()
+ {
+ int pos = out.position();
+ out.position(segment);
+ ByteBuffer slice = out.slice();
+ slice.limit(pos - segment);
+ out.position(pos);
+ return slice;
+ }
+
private void grow(int size)
{
ByteBuffer old = out;
int capacity = old.capacity();
out = ByteBuffer.allocate(Math.max(capacity + size, 2*capacity));
out.order(ByteOrder.BIG_ENDIAN);
+ old.flip();
out.put(old);
}
@@ -229,4 +239,96 @@ public final class BBEncoder extends AbstractEncoder
out.putInt(pos, (cur - pos - 4));
}
-}
+ public void writeDouble(double aDouble)
+ {
+ try
+ {
+ out.putDouble(aDouble);
+ } catch(BufferOverflowException exception)
+ {
+ grow(8);
+ out.putDouble(aDouble);
+ }
+ }
+
+ public void writeInt16(short aShort)
+ {
+ try
+ {
+ out.putShort(aShort);
+ } catch(BufferOverflowException exception)
+ {
+ grow(2);
+ out.putShort(aShort);
+ }
+ }
+
+ public void writeInt32(int anInt)
+ {
+ try
+ {
+ out.putInt(anInt);
+ } catch(BufferOverflowException exception)
+ {
+ grow(4);
+ out.putInt(anInt);
+ }
+ }
+
+ public void writeInt64(long aLong)
+ {
+ try
+ {
+ out.putLong(aLong);
+ } catch(BufferOverflowException exception)
+ {
+ grow(8);
+ out.putLong(aLong);
+ }
+ }
+
+ public void writeInt8(byte aByte)
+ {
+ try
+ {
+ out.put(aByte);
+ } catch(BufferOverflowException exception)
+ {
+ grow(1);
+ out.put(aByte);
+ }
+ }
+
+ public void writeBin128(byte[] byteArray)
+ {
+ byteArray = (byteArray != null) ? byteArray : new byte [16];
+
+ assert byteArray.length == 16;
+
+ try
+ {
+ out.put(byteArray);
+ } catch(BufferOverflowException exception)
+ {
+ grow(16);
+ out.put(byteArray);
+ }
+ }
+
+ public void writeFloat(float aFloat)
+ {
+ try
+ {
+ out.putFloat(aFloat);
+ } catch(BufferOverflowException exception)
+ {
+ grow(4);
+ out.putFloat(aFloat);
+ }
+ }
+
+ public void writeMagicNumber()
+ {
+ out.put("AM2".getBytes());
+ }
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/transport/codec/Decoder.java b/java/common/src/main/java/org/apache/qpid/transport/codec/Decoder.java
index 50e787ccb2..a4df5b5fcb 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/codec/Decoder.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/codec/Decoder.java
@@ -29,40 +29,255 @@ import org.apache.qpid.transport.Struct;
/**
- * Decoder
- *
+ * Decoder interface.
+ * Each concrete implementor must specify how to decode given values.
+ *
* @author Rafael H. Schloming
*/
-
public interface Decoder
{
-
+ /**
+ * Tells whether there are any remaining byte(s) to be read.
+ *
+ * @return true if there are remaining bytes, false otherwise.
+ */
boolean hasRemaining();
+ /**
+ * The uint8 type is an 8-bit unsigned integral value.
+ *
+ * @return an 8-bit unsigned integral value.
+ */
short readUint8();
+
+ /**
+ *The uint16 type is a 16-bit unsigned integral value encoded in network byte order.
+ *
+ * @return a 16-bit unsigned integral value encoded in network byte order.
+ */
int readUint16();
+
+ /**
+ *The uint32 type is a 32-bit unsigned integral value encoded in network byte order.
+ *
+ * @return a 32-bit unsigned integral value encoded in network byte order.
+ */
long readUint32();
+
+ /**
+ * The uint64 type is a 64-bit unsigned integral value encoded in network byte order.
+ *
+ * @return a 64-bit unsigned integral value encoded in network byte order.
+ */
long readUint64();
+ /**
+ * The datetime type encodes a date and time using the 64 bit POSIX time_t format.
+ *
+ * @return a date and time using the 64 bit POSIX time_t format.
+ */
long readDatetime();
+
+ /**
+ * The uuid type encodes a universally unique id as defined by RFC-4122.
+ * The format and operations for this type can be found in section 4.1.2 of RFC-4122.
+ *
+ * return a universally unique id as defined by RFC-4122.
+ */
UUID readUuid();
+ /**
+// *The sequence-no type encodes, in network byte order, a serial number as defined in RFC-1982.
+ *
+ * @return a serial number as defined in RFC-1982.
+ */
int readSequenceNo();
+
RangeSet readSequenceSet(); // XXX
RangeSet readByteRanges(); // XXX
+ /**
+ * The str8 type encodes up to 255 octets worth of UTF-8 unicode.
+ * The number of octets of unicode is first encoded as an 8-bit unsigned integral value.
+ * This is followed by the actual UTF-8 unicode.
+ * Note that the encoded size refers to the number of octets of unicode, not necessarily the number of characters since
+ * the UTF-8 unicode may include multi-byte character sequences.
+ *
+ * @return a string.
+ */
String readStr8();
+
+ /**
+ * The str16 type encodes up to 65535 octets worth of UTF-8 unicode.
+ * The number of octets is first encoded as a 16-bit unsigned integral value in network byte order.
+ * This is followed by the actual UTF-8 unicode.
+ * Note that the encoded size refers to the number of octets of unicode, not necessarily the number of unicode
+ * characters since the UTF-8 unicode may include multi-byte character sequences.
+ *
+ * return a string.
+ */
String readStr16();
+ /**
+ * The vbin8 type encodes up to 255 octets of opaque binary data.
+ *
+ * return a byte array.
+ */
byte[] readVbin8();
+
+ /**
+ * The vbin16 type encodes up to 65535 octets of opaque binary data.
+ *
+ * @return the corresponding byte array.
+ */
byte[] readVbin16();
+
+ /**
+ * The vbin32 type encodes up to 4294967295 octets of opaque binary data.
+ *
+ * @return the corresponding byte array.
+ */
byte[] readVbin32();
+ /**
+ * The struct32 type describes any coded struct with a 32-bit (4 octet) size.
+ * The type is restricted to be only coded structs with a 32-bit size, consequently the first six octets of any encoded
+ * value for this type MUST always contain the size, class-code, and struct-code in that order.
+ * The size is encoded as a 32-bit unsigned integral value in network byte order that is equal to the size of the
+ * encoded field-data, packing-flags, class-code, and struct-code. The class-code is a single octet that may be set to any
+ * valid class code.
+ * The struct-code is a single octet that may be set to any valid struct code within the given class-code.
+ * The first six octets are then followed by the packing flags and encoded field data.
+ * The presence and quantity of packingflags, as well as the specific fields are determined by the struct definition
+ * identified with the encoded class-code and struct-code.
+ *
+ * @return the decoded struct.
+ */
Struct readStruct32();
+
+ /**
+ * A map is a set of distinct keys where each key has an associated (type,value) pair.
+ * The triple of the key, type, and value, form an entry within a map. Each entry within a given map MUST have a
+ * distinct key.
+ * A map is encoded as a size in octets, a count of the number of entries, followed by the encoded entries themselves.
+ * An encoded map may contain up to (4294967295 - 4) octets worth of encoded entries.
+ * The size is encoded as a 32-bit unsigned integral value in network byte order equal to the number of octets worth of
+ * encoded entries plus 4. (The extra 4 octets is added for the entry count.)
+ * The size is then followed by the number of entries encoded as a 32-bit unsigned integral value in network byte order.
+ * Finally the entries are encoded sequentially.
+ * An entry is encoded as the key, followed by the type, and then the value. The key is always a string encoded as a str8.
+ * The type is a single octet that may contain any valid AMQP type code.
+ * The value is encoded according to the rules defined by the type code for that entry.
+ *
+ * @return the decoded map.
+ */
Map<String,Object> readMap();
+
+ /**
+ * A list is an ordered sequence of (type, value) pairs. The (type, value) pair forms an item within the list.
+ * The list may contain items of many distinct types. A list is encoded as a size in octets, followed by a count of the
+ * number of items, followed by the items themselves encoded in their defined order.
+ * An encoded list may contain up to (4294967295 - 4) octets worth of encoded items.
+ * The size is encoded as a 32-bit unsigned integral value in network byte order equal to the number of octets worth
+ * of encoded items plus 4. (The extra4 octets is added for the item count.)
+ * The size is then followed by the number of items encoded as a 32-bit unsigned integral value in network byte order.
+ * Finally the items are encoded sequentially in their defined order.
+ * An item is encoded as the type followed by the value. The type is a single octet that may contain any valid AMQP type
+ * code.
+ * The value is encoded according to the rules defined by the type code for that item.
+ *
+ * @return the decoded list.
+ */
List<Object> readList();
+
+ /**
+ * An array is an ordered sequence of values of the same type.
+ * The array is encoded in as a size in octets, followed by a type code, then a count of the number values in the array,
+ * and finally the values encoded in their defined order.
+ * An encoded array may contain up to (4294967295 - 5) octets worth of encoded values.
+ * The size is encoded as a 32-bit unsigned integral value in network byte order equal to the number of octets worth of
+ * encoded values plus 5. (The extra 5 octets consist of 4 octets for the count of the number of values, and one octet to
+ * hold the type code for the items inthe array.)
+ * The size is then followed by a single octet that may contain any valid AMQP type code.
+ * The type code is then followed by the number of values encoded as a 32-bit unsigned integral value in network byte
+ * order.
+ * Finally the values are encoded sequentially in their defined order according to the rules defined by the type code for
+ * the array.
+ *
+ * @return the decoded array.
+ */
List<Object> readArray();
+ /**
+ *
+ * @param type the type of the struct.
+ * @return the decoded struct.
+ */
Struct readStruct(int type);
-
-}
+
+ /**
+ * The float type encodes a single precision 32-bit floating point number.
+ * The format and operations are defined by the IEEE 754 standard for 32-bit single precision floating point numbers.
+ *
+ * @return the decoded float.
+ */
+ float readFloat();
+
+ /**
+ * The double type encodes a double precision 64-bit floating point number.
+ * The format and operations are defined by the IEEE 754 standard for 64-bit double precision floating point numbers.
+ *
+ * @return the decoded double
+ */
+ double readDouble();
+
+ /**
+ * The int8 type is a signed integral value encoded using an 8-bit two's complement representation.
+ *
+ * @return the decoded integer.
+ */
+ byte readInt8();
+
+ /**
+ * The int16 type is a signed integral value encoded using a 16-bit two's complement representation in network byte order.
+ *
+ * @return the decoded integer.
+ */
+ short readInt16();
+
+ /**
+ * The int32 type is a signed integral value encoded using a 32-bit two's complement representation in network byte order.
+ *
+ * @return the decoded integer.
+ */
+ int readInt32();
+
+ /**
+ * The int64 type is a signed integral value encoded using a 64-bit two's complement representation in network byte order.
+ *
+ * @return the decoded integer (as long).
+ */
+ long readInt64();
+
+ /**
+ * The bin128 type consists of 16 consecutive octets of opaque binary data.
+ *
+ * @return the decoded byte array.
+ */
+ byte [] readBin128();
+
+ /**
+ * Reads the remaining bytes on the underlying buffer.
+ *
+ * @return the remaining bytes on the underlying buffer.
+ */
+ byte[] readReaminingBytes ();
+
+ /**
+ * Reads the given number of bytes.
+ *
+ * @param howManyBytes how many bytes need to be read?
+ * @return a byte array containing the requested data.
+ */
+ byte[] readBytes (int howManyBytes);
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/transport/codec/Encodable.java b/java/common/src/main/java/org/apache/qpid/transport/codec/Encodable.java
index 2aefafd19c..37ce8a5cb7 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/codec/Encodable.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/codec/Encodable.java
@@ -26,12 +26,19 @@ package org.apache.qpid.transport.codec;
*
* @author Rafael H. Schloming
*/
-
public interface Encodable
{
+ /**
+ * Encodes this encodable using the given encoder.
+ *
+ * @param encoder the encoder.
+ */
+ void write(Encoder encoder);
- void write(Encoder enc);
-
- void read(Decoder dec);
-
-}
+ /**
+ * Decodes this encodable using the given decoder.
+ *
+ * @param decoder the decoder.
+ */
+ void read(Decoder decoder);
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/transport/codec/Encoder.java b/java/common/src/main/java/org/apache/qpid/transport/codec/Encoder.java
index 2d8d13e80a..7d4f02af31 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/codec/Encoder.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/codec/Encoder.java
@@ -29,38 +29,254 @@ import org.apache.qpid.transport.Struct;
/**
- * Encoder
+ * Encoder interface.
+ * Each concrete implementor must specify how to encode given values.
*
* @author Rafael H. Schloming
*/
-
public interface Encoder
{
-
+ /**
+ * The uint8 type is an 8-bit unsigned integral value.
+ *
+ * @param b the unsigned integer to be encoded.
+ */
void writeUint8(short b);
+
+ /**
+ *The uint16 type is a 16-bit unsigned integral value encoded in network byte order.
+ *
+ * @param s the unsigned integer to be encoded.
+ */
void writeUint16(int s);
+
+ /**
+ *The uint32 type is a 32-bit unsigned integral value encoded in network byte order.
+ *
+ * @param i the unsigned integer to be encoded.
+ */
void writeUint32(long i);
+
+ /**
+ * The uint64 type is a 64-bit unsigned integral value encoded in network byte order.
+ *
+ * @param b the unsigned integer to be encoded.
+ */
void writeUint64(long l);
+ /**
+ * The datetime type encodes a date and time using the 64 bit POSIX time_t format.
+ *
+ * @param l the datetime (as long) to be encoded.
+ */
void writeDatetime(long l);
+
+ /**
+ * The uuid type encodes a universally unique id as defined by RFC-4122.
+ * The format and operations for this type can be found in section 4.1.2 of RFC-4122.
+ *
+ * @param uuid the uuid to be encoded.
+ */
void writeUuid(UUID uuid);
+ /**
+ *The sequence-no type encodes, in network byte order, a serial number as defined in RFC-1982.
+ *
+ * @param s the sequence number to be encoded.
+ */
void writeSequenceNo(int s);
+
void writeSequenceSet(RangeSet ranges); // XXX
void writeByteRanges(RangeSet ranges); // XXX
+ /**
+ * The str8 type encodes up to 255 octets worth of UTF-8 unicode.
+ * The number of octets of unicode is first encoded as an 8-bit unsigned integral value.
+ * This is followed by the actual UTF-8 unicode.
+ * Note that the encoded size refers to the number of octets of unicode, not necessarily the number of characters since
+ * the UTF-8 unicode may include multi-byte character sequences.
+ *
+ * @param s the string to be encoded.
+ */
void writeStr8(String s);
+
+ /**
+ * The str16 type encodes up to 65535 octets worth of UTF-8 unicode.
+ * The number of octets is first encoded as a 16-bit unsigned integral value in network byte order.
+ * This is followed by the actual UTF-8 unicode.
+ * Note that the encoded size refers to the number of octets of unicode, not necessarily the number of unicode
+ * characters since the UTF-8 unicode may include multi-byte character sequences.
+ *
+ * @param s the string to be encoded.
+ */
void writeStr16(String s);
+ /**
+ * The vbin8 type encodes up to 255 octets of opaque binary data.
+ * The number of octets is first encoded as an 8-bit unsigned integral value.
+ * This is followed by the actual data.
+ *
+ * @param bytes the byte array to be encoded.
+ */
void writeVbin8(byte[] bytes);
+
+ /**
+ * The vbin16 type encodes up to 65535 octets of opaque binary data.
+ * The number of octets is first encoded as a 16-bit unsigned integral value in network byte order.
+ * This is followed by the actual data.
+ *
+ * @param bytes the byte array to be encoded.
+ */
void writeVbin16(byte[] bytes);
+
+ /**
+ * The vbin32 type encodes up to 4294967295 octets of opaque binary data.
+ * The number of octets is first encoded as a 32-bit unsigned integral value in network byte order.
+ * This is followed by the actual data.
+ *
+ * @param bytes the byte array to be encoded.
+ */
void writeVbin32(byte[] bytes);
- void writeStruct32(Struct s);
+ /**
+ * The struct32 type describes any coded struct with a 32-bit (4 octet) size.
+ * The type is restricted to be only coded structs with a 32-bit size, consequently the first six octets of any encoded
+ * value for this type MUST always contain the size, class-code, and struct-code in that order.
+ * The size is encoded as a 32-bit unsigned integral value in network byte order that is equal to the size of the
+ * encoded field-data, packing-flags, class-code, and struct-code. The class-code is a single octet that may be set to any
+ * valid class code.
+ * The struct-code is a single octet that may be set to any valid struct code within the given class-code.
+ * The first six octets are then followed by the packing flags and encoded field data.
+ * The presence and quantity of packingflags, as well as the specific fields are determined by the struct definition
+ * identified with the encoded class-code and struct-code.
+ *
+ * @param struct the struct to be encoded.
+ */
+ void writeStruct32(Struct struct);
+
+ /**
+ * A map is a set of distinct keys where each key has an associated (type,value) pair.
+ * The triple of the key, type, and value, form an entry within a map. Each entry within a given map MUST have a
+ * distinct key.
+ * A map is encoded as a size in octets, a count of the number of entries, followed by the encoded entries themselves.
+ * An encoded map may contain up to (4294967295 - 4) octets worth of encoded entries.
+ * The size is encoded as a 32-bit unsigned integral value in network byte order equal to the number of octets worth of
+ * encoded entries plus 4. (The extra 4 octets is added for the entry count.)
+ * The size is then followed by the number of entries encoded as a 32-bit unsigned integral value in network byte order.
+ * Finally the entries are encoded sequentially.
+ * An entry is encoded as the key, followed by the type, and then the value. The key is always a string encoded as a str8.
+ * The type is a single octet that may contain any valid AMQP type code.
+ * The value is encoded according to the rules defined by the type code for that entry.
+ *
+ * @param map the map to be encoded.
+ */
void writeMap(Map<String,Object> map);
+
+ /**
+ * A list is an ordered sequence of (type, value) pairs. The (type, value) pair forms an item within the list.
+ * The list may contain items of many distinct types. A list is encoded as a size in octets, followed by a count of the
+ * number of items, followed by the items themselves encoded in their defined order.
+ * An encoded list may contain up to (4294967295 - 4) octets worth of encoded items.
+ * The size is encoded as a 32-bit unsigned integral value in network byte order equal to the number of octets worth
+ * of encoded items plus 4. (The extra4 octets is added for the item count.)
+ * The size is then followed by the number of items encoded as a 32-bit unsigned integral value in network byte order.
+ * Finally the items are encoded sequentially in their defined order.
+ * An item is encoded as the type followed by the value. The type is a single octet that may contain any valid AMQP type
+ * code.
+ * The value is encoded according to the rules defined by the type code for that item.
+ *
+ * @param list the list to be encoded.
+ */
void writeList(List<Object> list);
+
+ /**
+ * An array is an ordered sequence of values of the same type.
+ * The array is encoded in as a size in octets, followed by a type code, then a count of the number values in the array,
+ * and finally the values encoded in their defined order.
+ * An encoded array may contain up to (4294967295 - 5) octets worth of encoded values.
+ * The size is encoded as a 32-bit unsigned integral value in network byte order equal to the number of octets worth of
+ * encoded values plus 5. (The extra 5 octets consist of 4 octets for the count of the number of values, and one octet to
+ * hold the type code for the items inthe array.)
+ * The size is then followed by a single octet that may contain any valid AMQP type code.
+ * The type code is then followed by the number of values encoded as a 32-bit unsigned integral value in network byte
+ * order.
+ * Finally the values are encoded sequentially in their defined order according to the rules defined by the type code for
+ * the array.
+ *
+ * @param array the array to be encoded.
+ */
void writeArray(List<Object> array);
- void writeStruct(int type, Struct s);
-
-}
+ /**
+ * The struct32 type describes any coded struct with a 32-bit (4 octet) size.
+ * The type is restricted to be only coded structs with a 32-bit size, consequently the first six octets of any encoded
+ * value for this type MUST always contain the size, class-code, and struct-code in that order.
+ * The size is encoded as a 32-bit unsigned integral value in network byte order that is equal to the size of the
+ * encoded field-data, packing-flags, class-code, and struct-code. The class-code is a single octet that may be set to any
+ * valid class code.
+ * The struct-code is a single octet that may be set to any valid struct code within the given class-code.
+ * The first six octets are then followed by the packing flags and encoded field data.
+ * The presence and quantity of packingflags, as well as the specific fields are determined by the struct definition
+ * identified with the encoded class-code and struct-code.
+ *
+ * @param type the type of the struct.
+ * @param struct the struct to be encoded.
+ */
+ void writeStruct(int type, Struct struct);
+
+ /**
+ * The float type encodes a single precision 32-bit floating point number.
+ * The format and operations are defined by the IEEE 754 standard for 32-bit single precision floating point numbers.
+ *
+ * @param aFloat the float to be encoded.
+ */
+ void writeFloat(float aFloat);
+
+ /**
+ * The double type encodes a double precision 64-bit floating point number.
+ * The format and operations are defined by the IEEE 754 standard for 64-bit double precision floating point numbers.
+ *
+ * @param aDouble the double to be encoded.
+ */
+ void writeDouble(double aDouble);
+
+ /**
+ * The int8 type is a signed integral value encoded using an 8-bit two's complement representation.
+ *
+ * @param aByte the integer to be encoded.
+ */
+ void writeInt8(byte aByte);
+
+ /**
+ * The int16 type is a signed integral value encoded using a 16-bit two's complement representation in network byte order.
+ *
+ * @param aShort the integer to be encoded.
+ */
+ void writeInt16(short aShort);
+
+ /**
+ * The int32 type is a signed integral value encoded using a 32-bit two's complement representation in network byte order.
+ *
+ * @param anInt the integer to be encoded.
+ */
+ void writeInt32(int anInt);
+
+ /**
+ * The int64 type is a signed integral value encoded using a 64-bit two's complement representation in network byte order.
+ *
+ * @param aLong the integer to be encoded.
+ */
+ void writeInt64(long aLong);
+
+ /**
+ * The bin128 type consists of 16 consecutive octets of opaque binary data.
+ *
+ * @param bytes the bytes array to be encoded.
+ */
+ void writeBin128(byte [] bytes);
+
+ /**
+ * Encodes the AMQP magic number.
+ */
+ void writeMagicNumber();
+} \ No newline at end of file
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/Assembler.java b/java/common/src/main/java/org/apache/qpid/transport/network/Assembler.java
index 4ff8fec206..357caa26e1 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/Assembler.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/Assembler.java
@@ -186,10 +186,11 @@ public class Assembler implements Receiver<NetworkEvent>, NetworkDelegate
case COMMAND:
int commandType = dec.readUint16();
// read in the session header, right now we don't use it
- dec.readUint16();
+ int hdr = dec.readUint16();
command = Method.create(commandType);
+ command.setSync((0x0001 & hdr) != 0);
command.read(dec);
- if (command.hasPayloadSegment())
+ if (command.hasPayload())
{
incomplete[channel] = command;
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/ConnectionBinding.java b/java/common/src/main/java/org/apache/qpid/transport/network/ConnectionBinding.java
index 6886cb3a5a..8a2aba2e6d 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/ConnectionBinding.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/ConnectionBinding.java
@@ -33,23 +33,46 @@ import org.apache.qpid.transport.Sender;
*
*/
-public class ConnectionBinding implements Binding<Connection,ByteBuffer>
+public abstract class ConnectionBinding
+ implements Binding<Connection,ByteBuffer>
{
- private static final int MAX_FRAME_SIZE = 64 * 1024 - 1;
-
- private final ConnectionDelegate delegate;
+ public static Binding<Connection,ByteBuffer> get(final Connection connection)
+ {
+ return new ConnectionBinding()
+ {
+ public Connection connection()
+ {
+ return connection;
+ }
+ };
+ }
- public ConnectionBinding(ConnectionDelegate delegate)
+ public static Binding<Connection,ByteBuffer> get(final ConnectionDelegate delegate)
{
- this.delegate = delegate;
+ return new ConnectionBinding()
+ {
+ public Connection connection()
+ {
+ Connection conn = new Connection();
+ conn.setConnectionDelegate(delegate);
+ return conn;
+ }
+ };
}
+ public static final int MAX_FRAME_SIZE = 64 * 1024 - 1;
+
+ public abstract Connection connection();
+
public Connection endpoint(Sender<ByteBuffer> sender)
{
+ Connection conn = connection();
+
// XXX: hardcoded max-frame
- return new Connection
- (new Disassembler(sender, MAX_FRAME_SIZE), delegate);
+ Disassembler dis = new Disassembler(sender, MAX_FRAME_SIZE);
+ conn.setSender(dis);
+ return conn;
}
public Receiver<ByteBuffer> receiver(Connection conn)
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java b/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java
index 09586b357a..d99ee72d14 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/Disassembler.java
@@ -20,7 +20,15 @@
*/
package org.apache.qpid.transport.network;
-import org.apache.qpid.transport.codec.BBEncoder;
+import static java.lang.Math.min;
+import static org.apache.qpid.transport.network.Frame.FIRST_FRAME;
+import static org.apache.qpid.transport.network.Frame.FIRST_SEG;
+import static org.apache.qpid.transport.network.Frame.HEADER_SIZE;
+import static org.apache.qpid.transport.network.Frame.LAST_FRAME;
+import static org.apache.qpid.transport.network.Frame.LAST_SEG;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import org.apache.qpid.transport.Header;
import org.apache.qpid.transport.Method;
@@ -31,13 +39,7 @@ import org.apache.qpid.transport.ProtocolHeader;
import org.apache.qpid.transport.SegmentType;
import org.apache.qpid.transport.Sender;
import org.apache.qpid.transport.Struct;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-
-import static org.apache.qpid.transport.network.Frame.*;
-
-import static java.lang.Math.*;
+import org.apache.qpid.transport.codec.BBEncoder;
/**
@@ -198,7 +200,7 @@ public final class Disassembler implements Sender<ProtocolEvent>,
byte flags = FIRST_SEG;
- boolean payload = method.hasPayloadSegment();
+ boolean payload = method.hasPayload();
if (!payload)
{
flags |= LAST_SEG;
@@ -208,11 +210,14 @@ public final class Disassembler implements Sender<ProtocolEvent>,
if (payload)
{
final Header hdr = method.getHeader();
- final Struct[] structs = hdr.getStructs();
-
- for (Struct st : structs)
+ if (hdr != null)
{
- enc.writeStruct32(st);
+ final Struct[] structs = hdr.getStructs();
+
+ for (Struct st : structs)
+ {
+ enc.writeStruct32(st);
+ }
}
headerSeg = enc.segment();
}
@@ -232,5 +237,9 @@ public final class Disassembler implements Sender<ProtocolEvent>,
{
throw new IllegalArgumentException("" + error);
}
-
+
+ public void setIdleTimeout(long l)
+ {
+ sender.setIdleTimeout(l);
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/InputHandler.java b/java/common/src/main/java/org/apache/qpid/transport/network/InputHandler.java
index 408c95e075..a2885f97bc 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/InputHandler.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/InputHandler.java
@@ -39,7 +39,7 @@ import static org.apache.qpid.transport.network.InputHandler.State.*;
* @author Rafael H. Schloming
*/
-public final class InputHandler implements Receiver<ByteBuffer>
+public class InputHandler implements Receiver<ByteBuffer>
{
public enum State
@@ -144,10 +144,11 @@ public final class InputHandler implements Receiver<ByteBuffer>
return ERROR;
}
+ byte protoClass = input.get(pos + 4);
byte instance = input.get(pos + 5);
byte major = input.get(pos + 6);
byte minor = input.get(pos + 7);
- receiver.received(new ProtocolHeader(instance, major, minor));
+ receiver.received(new ProtocolHeader(protoClass, instance, major, minor));
needed = Frame.HEADER_SIZE;
return FRAME_HDR;
case FRAME_HDR:
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
index b63020913b..ecc5f6d07c 100644
--- 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
@@ -1,4 +1,25 @@
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;
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoAcceptor.java b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoAcceptor.java
index c4559ae6b4..8530240dcc 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/network/io/IoAcceptor.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/io/IoAcceptor.java
@@ -56,6 +56,17 @@ public class IoAcceptor<E> extends Thread
setName(String.format("IoAcceptor - %s", socket.getInetAddress()));
}
+ /**
+ Close the underlying ServerSocket if it has not already been closed.
+ */
+ public void close() throws IOException
+ {
+ if (!socket.isClosed())
+ {
+ socket.close();
+ }
+ }
+
public IoAcceptor(String host, int port, Binding<E,ByteBuffer> binding)
throws IOException
{
@@ -69,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/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 a1fb0371fd..6144edb947 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,13 +20,15 @@
*/
package org.apache.qpid.transport.network.io;
+import org.apache.qpid.thread.Threading;
import org.apache.qpid.transport.Receiver;
import org.apache.qpid.transport.TransportException;
import org.apache.qpid.transport.util.Logger;
-import java.io.InputStream;
import java.io.IOException;
+import java.io.InputStream;
import java.net.Socket;
+import java.net.SocketException;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -35,7 +37,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
*
*/
-final class IoReceiver extends Thread
+final class IoReceiver implements Runnable
{
private static final Logger log = Logger.get(IoReceiver.class);
@@ -46,6 +48,9 @@ final class IoReceiver extends Thread
private final Socket socket;
private final long timeout;
private final AtomicBoolean closed = new AtomicBoolean(false);
+ private final Thread receiverThread;
+ private final boolean shutdownBroken =
+ ((String) System.getProperties().get("os.name")).matches("(?i).*windows.*");
public IoReceiver(IoTransport transport, Receiver<ByteBuffer> receiver,
int bufferSize, long timeout)
@@ -55,19 +60,27 @@ final class IoReceiver extends Thread
this.bufferSize = bufferSize;
this.socket = transport.getSocket();
this.timeout = timeout;
-
- setDaemon(true);
- setName(String.format("IoReceiver - %s", socket.getRemoteSocketAddress()));
- start();
+
+ try
+ {
+ receiverThread = Threading.getThreadFactory().createThread(this);
+ }
+ catch(Exception e)
+ {
+ throw new Error("Error creating IOReceiver thread",e);
+ }
+ receiverThread.setDaemon(true);
+ receiverThread.setName(String.format("IoReceiver - %s", socket.getRemoteSocketAddress()));
+ receiverThread.start();
}
- void close()
+ void close(boolean block)
{
if (!closed.getAndSet(true))
{
try
{
- if (((String) System.getProperties().get("os.name")).matches("(?i).*windows.*"))
+ if (shutdownBroken)
{
socket.close();
}
@@ -75,10 +88,10 @@ final class IoReceiver extends Thread
{
socket.shutdownInput();
}
- if (Thread.currentThread() != this)
+ if (block && Thread.currentThread() != receiverThread)
{
- join(timeout);
- if (isAlive())
+ receiverThread.join(timeout);
+ if (receiverThread.isAlive())
{
throw new TransportException("join timed out");
}
@@ -124,12 +137,25 @@ final class IoReceiver extends Thread
}
catch (Throwable t)
{
- receiver.exception(t);
+ if (!(shutdownBroken &&
+ t instanceof SocketException &&
+ t.getMessage().equalsIgnoreCase("socket closed") &&
+ closed.get()))
+ {
+ receiver.exception(t);
+ }
}
finally
{
receiver.closed();
- transport.getSender().close();
+ try
+ {
+ socket.close();
+ }
+ catch(Exception e)
+ {
+ log.warn(e, "Error closing socket");
+ }
}
}
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 ef892744ab..00652e2927 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
@@ -18,20 +18,22 @@
*/
package org.apache.qpid.transport.network.io;
+import static org.apache.qpid.transport.util.Functions.mod;
+
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicBoolean;
+import org.apache.qpid.thread.Threading;
import org.apache.qpid.transport.Sender;
+import org.apache.qpid.transport.SenderException;
import org.apache.qpid.transport.TransportException;
import org.apache.qpid.transport.util.Logger;
-import static org.apache.qpid.transport.util.Functions.*;
-
-public final class IoSender extends Thread implements Sender<ByteBuffer>
+public final class IoSender implements Runnable, Sender<ByteBuffer>
{
private static final Logger log = Logger.get(IoSender.class);
@@ -53,7 +55,9 @@ public final class IoSender extends Thread implements Sender<ByteBuffer>
private final Object notFull = new Object();
private final Object notEmpty = new Object();
private final AtomicBoolean closed = new AtomicBoolean(false);
-
+ private final Thread senderThread;
+ private long idleTimeout;
+
private volatile Throwable exception = null;
@@ -73,9 +77,18 @@ public final class IoSender extends Thread implements Sender<ByteBuffer>
throw new TransportException("Error getting output stream for socket", e);
}
- setDaemon(true);
- setName(String.format("IoSender - %s", socket.getRemoteSocketAddress()));
- start();
+ try
+ {
+ 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()));
+ senderThread.start();
}
private static final int pof2(int n)
@@ -88,17 +101,11 @@ public final class IoSender extends Thread implements Sender<ByteBuffer>
return result;
}
- private static final int mod(int n, int m)
- {
- int r = n % m;
- return r < 0 ? m + r : r;
- }
-
public void send(ByteBuffer buf)
{
if (closed.get())
{
- throw new TransportException("sender is closed", exception);
+ throw new SenderException("sender is closed", exception);
}
final int size = buffer.length;
@@ -131,12 +138,12 @@ public final class IoSender extends Thread implements Sender<ByteBuffer>
if (closed.get())
{
- throw new TransportException("sender is closed", exception);
+ throw new SenderException("sender is closed", exception);
}
if (head - tail >= size)
{
- throw new TransportException(String.format("write timed out: %s, %s", head, tail));
+ throw new SenderException(String.format("write timed out: %s, %s", head, tail));
}
}
continue;
@@ -181,6 +188,11 @@ public final class IoSender extends Thread implements Sender<ByteBuffer>
{
if (!closed.getAndSet(true))
{
+ synchronized (notFull)
+ {
+ notFull.notify();
+ }
+
synchronized (notEmpty)
{
notEmpty.notify();
@@ -188,37 +200,31 @@ public final class IoSender extends Thread implements Sender<ByteBuffer>
try
{
- if (Thread.currentThread() != this)
+ if (Thread.currentThread() != senderThread)
{
- join(timeout);
- if (isAlive())
+ senderThread.join(timeout);
+ if (senderThread.isAlive())
{
- throw new TransportException("join timed out");
+ throw new SenderException("join timed out");
}
}
- transport.getReceiver().close();
- socket.close();
+ transport.getReceiver().close(false);
}
catch (InterruptedException e)
{
- throw new TransportException(e);
- }
- catch (IOException e)
- {
- throw new TransportException(e);
+ throw new SenderException(e);
}
if (reportException && exception != null)
{
- throw new TransportException(exception);
+ throw new SenderException(exception);
}
}
}
public void run()
{
- final int size = buffer.length;
-
+ final int size = buffer.length;
while (true)
{
final int hd = head;
@@ -288,4 +294,16 @@ public final class IoSender extends Thread implements Sender<ByteBuffer>
}
}
+ public void setIdleTimeout(long l)
+ {
+ try
+ {
+ socket.setSoTimeout((int)l*2);
+ idleTimeout = l;
+ }
+ catch (Exception e)
+ {
+ throw new SenderException(e);
+ }
+ }
}
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
index 70fd8a3c06..3615461e9f 100644
--- 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
@@ -26,17 +26,20 @@ 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.Assembler;
import org.apache.qpid.transport.network.ConnectionBinding;
-import org.apache.qpid.transport.network.Disassembler;
-import org.apache.qpid.transport.network.InputHandler;
+import org.apache.qpid.transport.network.ssl.SSLReceiver;
+import org.apache.qpid.transport.network.ssl.SSLSender;
import org.apache.qpid.transport.util.Logger;
/**
@@ -68,21 +71,53 @@ public final class IoTransport<E>
("amqj.sendBufferSize", DEFAULT_READ_WRITE_BUFFER_SIZE);
private Socket socket;
- private IoSender sender;
+ private Sender<ByteBuffer> sender;
private E endpoint;
private IoReceiver receiver;
private long timeout = 60000;
- IoTransport(Socket socket, Binding<E,ByteBuffer> binding)
+ IoTransport(Socket socket, Binding<E,ByteBuffer> binding, boolean ssl)
{
this.socket = socket;
- this.sender = new IoSender(this, 2*writeBufferSize, timeout);
- this.endpoint = binding.endpoint(sender);
- this.receiver = new IoReceiver(this, binding.receiver(endpoint),
- 2*readBufferSize, timeout);
+
+ 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);
+ }
+ 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);
+ }
}
- IoSender getSender()
+ Sender<ByteBuffer> getSender()
{
return sender;
}
@@ -98,22 +133,24 @@ public final class IoTransport<E>
}
public static final <E> E connect(String host, int port,
- Binding<E,ByteBuffer> binding)
+ Binding<E,ByteBuffer> binding,
+ boolean ssl)
{
Socket socket = createSocket(host, port);
- IoTransport<E> transport = new IoTransport<E>(socket, binding);
+ IoTransport<E> transport = new IoTransport<E>(socket, binding,ssl);
return transport.endpoint;
}
public static final Connection connect(String host, int port,
- ConnectionDelegate delegate)
+ ConnectionDelegate delegate,
+ boolean ssl)
{
- return connect(host, port, new ConnectionBinding(delegate));
+ return connect(host, port, ConnectionBinding.get(delegate),ssl);
}
- public static void connect_0_9(AMQVersionAwareProtocolSession session, String host, int port)
+ public static void connect_0_9(AMQVersionAwareProtocolSession session, String host, int port, boolean ssl)
{
- connect(host, port, new Binding_0_9(session));
+ connect(host, port, new Binding_0_9(session),ssl);
}
private static class Binding_0_9
@@ -170,5 +207,23 @@ public final class IoTransport<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..3838bf76be
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/mina/MINANetworkDriver.java
@@ -0,0 +1,421 @@
+/*
+ *
+ * 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.BindException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.nio.ByteBuffer;
+
+import org.apache.mina.common.ConnectFuture;
+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.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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+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);
+
+ 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();
+ 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
+ }
+
+ org.apache.mina.common.ByteBuffer.setUseDirectBuffers(Boolean.getBoolean("amqj.enableDirectBuffers"));
+ // the MINA default is currently to use the pooled allocator although this may change in future
+ // once more testing of the performance of the simple allocator has been done
+ if (!Boolean.getBoolean("amqj.enablePooledAllocator"))
+ {
+ org.apache.mina.common.ByteBuffer.setAllocator(new SimpleByteBufferAllocator());
+ }
+
+ SocketConnectorConfig cfg = (SocketConnectorConfig) _socketConnector.getDefaultConfig();
+
+ 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(long l)
+ {
+ // 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
index f8dbec3c3d..b89eed48b0 100644
--- 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
@@ -262,13 +262,13 @@ public class MinaHandler<E> implements IoHandler
ConnectionDelegate delegate)
throws IOException
{
- accept(host, port, new ConnectionBinding(delegate));
+ accept(host, port, ConnectionBinding.get(delegate));
}
public static final Connection connect(String host, int port,
ConnectionDelegate delegate)
{
- return connect(host, port, new ConnectionBinding(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
index 69d4061e0c..fbedf14312 100644
--- 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
@@ -24,7 +24,6 @@ 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;
@@ -77,5 +76,15 @@ public class MinaSender implements Sender<java.nio.ByteBuffer>
CloseFuture closed = session.close();
closed.join();
}
-
+
+ public void setIdleTimeout(long l)
+ {
+ //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
index 51e41b26f7..3bc6730623 100644
--- 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
@@ -1,4 +1,25 @@
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.EOFException;
import java.io.IOException;
@@ -66,8 +87,9 @@ public class NioHandler implements Runnable
}
NioSender sender = new NioSender(_ch);
- Connection con = new Connection
- (new Disassembler(sender, 64*1024 - 1), delegate);
+ Connection con = new Connection();
+ con.setSender(new Disassembler(sender, 64*1024 - 1));
+ con.setConnectionDelegate(delegate);
con.setConnectionId(_count.incrementAndGet());
_handlers.put(con.getConnectionId(),sender);
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
index 33e888cc56..5196505c2d 100644
--- 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
@@ -1,4 +1,25 @@
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;
@@ -97,4 +118,9 @@ public class NioSender implements Sender<java.nio.ByteBuffer>
}
}
}
+
+ public void setIdleTimeout(long l)
+ {
+ //noop
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/ssl/SSLReceiver.java b/java/common/src/main/java/org/apache/qpid/transport/network/ssl/SSLReceiver.java
new file mode 100644
index 0000000000..e6e6c5f791
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/ssl/SSLReceiver.java
@@ -0,0 +1,184 @@
+/*
+*
+ * 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.ssl;
+
+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 org.apache.qpid.transport.Receiver;
+import org.apache.qpid.transport.TransportException;
+import org.apache.qpid.transport.util.Logger;
+
+public class SSLReceiver implements Receiver<ByteBuffer>
+{
+ 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 static final Logger log = Logger.get(SSLReceiver.class);
+
+ 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);
+ notificationToken = sender.getNotificationToken();
+ }
+
+ public void closed()
+ {
+ delegate.closed();
+ }
+
+ public void exception(Throwable t)
+ {
+ delegate.exception(t);
+ }
+
+ private ByteBuffer addPreviouslyUnreadData(ByteBuffer buf)
+ {
+ if (dataCached)
+ {
+ ByteBuffer b = ByteBuffer.allocate(localBuffer.remaining() + buf.remaining());
+ b.put(localBuffer);
+ b.put(buf);
+ b.flip();
+ dataCached = false;
+ return b;
+ }
+ else
+ {
+ return buf;
+ }
+ }
+
+ public void received(ByteBuffer buf)
+ {
+ ByteBuffer netData = addPreviouslyUnreadData(buf);
+
+ HandshakeStatus handshakeStatus;
+ Status status;
+
+ while (netData.hasRemaining())
+ {
+ try
+ {
+ SSLEngineResult result = engine.unwrap(netData, appData);
+ synchronized (notificationToken)
+ {
+ notificationToken.notifyAll();
+ }
+
+ int read = result.bytesProduced();
+ status = result.getStatus();
+ handshakeStatus = result.getHandshakeStatus();
+
+ if (read > 0)
+ {
+ int limit = appData.limit();
+ appData.limit(appData.position());
+ appData.position(appData.position() - read);
+
+ ByteBuffer data = appData.slice();
+
+ appData.limit(limit);
+ appData.position(appData.position() + read);
+
+ delegate.received(data);
+ }
+
+
+ switch(status)
+ {
+ case CLOSED:
+ synchronized(notificationToken)
+ {
+ notificationToken.notifyAll();
+ }
+ return;
+
+ case BUFFER_OVERFLOW:
+ appData = ByteBuffer.allocate(sslBufSize);
+ continue;
+
+ case BUFFER_UNDERFLOW:
+ localBuffer.clear();
+ localBuffer.put(netData);
+ localBuffer.flip();
+ dataCached = true;
+ break;
+
+ case OK:
+ break; // do nothing
+
+ default:
+ throw new IllegalStateException("SSLReceiver: Invalid State " + status);
+ }
+
+ switch (handshakeStatus)
+ {
+ case NEED_UNWRAP:
+ if (netData.hasRemaining())
+ {
+ continue;
+ }
+ break;
+
+ case NEED_TASK:
+ sender.doTasks();
+ handshakeStatus = engine.getHandshakeStatus();
+
+ case NEED_WRAP:
+ case FINISHED:
+ case NOT_HANDSHAKING:
+ synchronized(notificationToken)
+ {
+ notificationToken.notifyAll();
+ }
+ break;
+
+ default:
+ throw new IllegalStateException("SSLReceiver: Invalid State " + status);
+ }
+
+
+ }
+ catch(SSLException e)
+ {
+ throw new TransportException("Error in SSLReceiver",e);
+ }
+
+ }
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/network/ssl/SSLSender.java b/java/common/src/main/java/org/apache/qpid/transport/network/ssl/SSLSender.java
new file mode 100644
index 0000000000..0e785bb2ee
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/network/ssl/SSLSender.java
@@ -0,0 +1,255 @@
+/*
+ * 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.ssl;
+
+import java.nio.ByteBuffer;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+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 org.apache.qpid.transport.Sender;
+import org.apache.qpid.transport.SenderException;
+import org.apache.qpid.transport.util.Logger;
+
+public class SSLSender implements Sender<ByteBuffer>
+{
+ private Sender<ByteBuffer> delegate;
+ private SSLEngine engine;
+ private int sslBufSize;
+ private ByteBuffer netData;
+ private long timeout = 30000;
+
+ private final Object engineState = new Object();
+ private final AtomicBoolean closed = new AtomicBoolean(false);
+
+ private static final Logger log = Logger.get(SSLSender.class);
+
+ 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);
+ }
+
+ public void close()
+ {
+ if (!closed.getAndSet(true))
+ {
+ if (engine.isOutboundDone())
+ {
+ return;
+ }
+ log.debug("Closing SSL connection");
+ engine.closeOutbound();
+ try
+ {
+ tearDownSSLConnection();
+ }
+ catch(Exception e)
+ {
+ throw new SenderException("Error closing SSL connection",e);
+ }
+
+ while (!engine.isOutboundDone())
+ {
+ synchronized(engineState)
+ {
+ try
+ {
+ engineState.wait();
+ }
+ catch(InterruptedException e)
+ {
+ // pass
+ }
+ }
+ }
+ delegate.close();
+ }
+ }
+
+ private void tearDownSSLConnection() throws Exception
+ {
+ SSLEngineResult result = engine.wrap(ByteBuffer.allocate(0), netData);
+ Status status = result.getStatus();
+ int read = result.bytesProduced();
+ while (status != Status.CLOSED)
+ {
+ if (status == Status.BUFFER_OVERFLOW)
+ {
+ netData.clear();
+ }
+ if(read > 0)
+ {
+ int limit = netData.limit();
+ netData.limit(netData.position());
+ netData.position(netData.position() - read);
+
+ ByteBuffer data = netData.slice();
+
+ netData.limit(limit);
+ netData.position(netData.position() + read);
+
+ delegate.send(data);
+ flush();
+ }
+ result = engine.wrap(ByteBuffer.allocate(0), netData);
+ status = result.getStatus();
+ read = result.bytesProduced();
+ }
+ }
+
+ public void flush()
+ {
+ delegate.flush();
+ }
+
+ public void send(ByteBuffer appData)
+ {
+ if (closed.get())
+ {
+ throw new SenderException("SSL Sender is closed");
+ }
+
+ HandshakeStatus handshakeStatus;
+ Status status;
+
+ while(appData.hasRemaining())
+ {
+
+ int read = 0;
+ try
+ {
+ SSLEngineResult result = engine.wrap(appData, netData);
+ read = result.bytesProduced();
+ status = result.getStatus();
+ handshakeStatus = result.getHandshakeStatus();
+
+ }
+ catch(SSLException e)
+ {
+ throw new SenderException("SSL, Error occurred while encrypting data",e);
+ }
+
+ if(read > 0)
+ {
+ int limit = netData.limit();
+ netData.limit(netData.position());
+ netData.position(netData.position() - read);
+
+ ByteBuffer data = netData.slice();
+
+ netData.limit(limit);
+ netData.position(netData.position() + read);
+
+ delegate.send(data);
+ }
+
+ switch(status)
+ {
+ case CLOSED:
+ throw new SenderException("SSLEngine is closed");
+
+ case BUFFER_OVERFLOW:
+ netData.clear();
+ continue;
+
+ case OK:
+ break; // do nothing
+
+ default:
+ throw new IllegalStateException("SSLReceiver: Invalid State " + status);
+ }
+
+ switch (handshakeStatus)
+ {
+ case NEED_WRAP:
+ if (netData.hasRemaining())
+ {
+ continue;
+ }
+
+ case NEED_TASK:
+ doTasks();
+ break;
+
+ case NEED_UNWRAP:
+ flush();
+ synchronized(engineState)
+ {
+ switch (engine.getHandshakeStatus())
+ {
+ case NEED_UNWRAP:
+ long start = System.currentTimeMillis();
+ try
+ {
+ engineState.wait(timeout);
+ }
+ catch(InterruptedException e)
+ {
+ // pass
+ }
+
+ if (System.currentTimeMillis()- start >= timeout)
+ {
+ throw new SenderException(
+ "SSL Engine timed out waiting for a response." +
+ "To get more info,run with -Djavax.net.debug=ssl");
+ }
+ break;
+ }
+ }
+ break;
+
+ case FINISHED:
+ case NOT_HANDSHAKING:
+ break; //do nothing
+
+ default:
+ throw new IllegalStateException("SSLReceiver: Invalid State " + status);
+ }
+
+ }
+ }
+
+ public void doTasks()
+ {
+ Runnable runnable;
+ while ((runnable = engine.getDelegatedTask()) != null) {
+ runnable.run();
+ }
+ }
+
+ public Object getNotificationToken()
+ {
+ return engineState;
+ }
+
+ public void setIdleTimeout(long l)
+ {
+ delegate.setIdleTimeout(l);
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpid/transport/util/Functions.java b/java/common/src/main/java/org/apache/qpid/transport/util/Functions.java
index 2c6984e302..9f1c0ca9eb 100644
--- a/java/common/src/main/java/org/apache/qpid/transport/util/Functions.java
+++ b/java/common/src/main/java/org/apache/qpid/transport/util/Functions.java
@@ -34,6 +34,12 @@ import static java.lang.Math.*;
public class Functions
{
+ public static final int mod(int n, int m)
+ {
+ int r = n % m;
+ return r < 0 ? m + r : r;
+ }
+
public static final byte lsb(int i)
{
return (byte) (0xFF & i);
@@ -51,12 +57,17 @@ public class Functions
public static final String str(ByteBuffer buf, int limit)
{
+ return str(buf, limit,buf.position());
+ }
+
+ public static final String str(ByteBuffer buf, int limit,int start)
+ {
StringBuilder str = new StringBuilder();
str.append('"');
for (int i = 0; i < min(buf.remaining(), limit); i++)
{
- byte c = buf.get(buf.position() + i);
+ byte c = buf.get(start + i);
if (c > 31 && c < 127 && c != '\\')
{
diff --git a/java/common/src/main/java/org/apache/qpid/transport/util/Waiter.java b/java/common/src/main/java/org/apache/qpid/transport/util/Waiter.java
new file mode 100644
index 0000000000..e034d779ca
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/transport/util/Waiter.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.util;
+
+
+/**
+ * Waiter
+ *
+ */
+
+public final class Waiter
+{
+
+ private final Object lock;
+ private final long timeout;
+ private final long start;
+ private long elapsed;
+
+ public Waiter(Object lock, long timeout)
+ {
+ this.lock = lock;
+ this.timeout = timeout;
+ this.start = System.currentTimeMillis();
+ this.elapsed = 0;
+ }
+
+ public boolean hasTime()
+ {
+ return elapsed < timeout;
+ }
+
+ public void await()
+ {
+ try
+ {
+ lock.wait(timeout - elapsed);
+ }
+ catch (InterruptedException e)
+ {
+ // pass
+ }
+ elapsed = System.currentTimeMillis() - start;
+ }
+
+}
diff --git a/java/common/src/main/java/org/apache/qpid/url/BindingURLImpl.java b/java/common/src/main/java/org/apache/qpid/url/BindingURLImpl.java
deleted file mode 100644
index f12fb2cff2..0000000000
--- a/java/common/src/main/java/org/apache/qpid/url/BindingURLImpl.java
+++ /dev/null
@@ -1,261 +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.url;
-
-import org.apache.qpid.exchange.ExchangeDefaults;
-import org.slf4j.LoggerFactory;
-import org.slf4j.Logger;
-
-import java.util.HashMap;
-import java.net.URI;
-import java.net.URISyntaxException;
-
-public class BindingURLImpl implements QpidBindingURL
-{
- private static final Logger _logger = LoggerFactory.getLogger(BindingURLImpl.class);
-
- String _url;
- String _exchangeClass;
- String _exchangeName;
- String _destinationName;
- String _queueName;
- private HashMap<String, String> _options;
-
- public BindingURLImpl(String url) throws URLSyntaxException
- {
- // format:
- // <exch_class>://<exch_name>/[<destination>]/[<queue>]?<option>='<value>'[,<option>='<value>']*
- if (_logger.isDebugEnabled())
- {
- _logger.debug("Parsing URL: " + url);
- }
- _url = url;
- _options = new HashMap<String, String>();
- parseBindingURL();
- }
-
- private void parseBindingURL() throws URLSyntaxException
- {
- try
- {
- URI connection = new URI(_url);
- String exchangeClass = connection.getScheme();
- if (exchangeClass == null)
- {
- _url = ExchangeDefaults.DIRECT_EXCHANGE_CLASS + "://" + "" + "//" + _url;
- // URLHelper.parseError(-1, "Exchange Class not specified.", _url);
- parseBindingURL();
- return;
- }
- else
- {
- setExchangeClass(exchangeClass);
- }
- String exchangeName = connection.getHost();
- if (exchangeName == null)
- {
- if (getExchangeClass().equals(ExchangeDefaults.DIRECT_EXCHANGE_CLASS))
- {
- setExchangeName("");
- }
- else
- {
- throw URLHelper.parseError(-1, "Exchange Name not specified.", _url);
- }
- }
- else
- {
- setExchangeName(exchangeName);
- }
- String queueName;
- if ((connection.getPath() == null) || connection.getPath().equals(""))
- {
- throw URLHelper.parseError(_url.indexOf(_exchangeName) + _exchangeName.length(),
- "Destination or Queue requried", _url);
- }
- else
- {
- int slash = connection.getPath().indexOf("/", 1);
- if (slash == -1)
- {
- throw URLHelper.parseError(_url.indexOf(_exchangeName) + _exchangeName.length(),
- "Destination requried", _url);
- }
- else
- {
- String path = connection.getPath();
- setDestinationName(path.substring(1, slash));
-
- // We don't set queueName yet as the actual value we use depends on options set
- // when we are dealing with durable subscriptions
-
- queueName = path.substring(slash + 1);
-
- }
- }
-
- URLHelper.parseOptions(_options, connection.getQuery());
- processOptions();
- // We can now call setQueueName as the URL is full parsed.
- setQueueName(queueName);
- // Fragment is #string (not used)
- if (_logger.isDebugEnabled())
- {
- _logger.debug("URL Parsed: " + this);
- }
- }
- catch (URISyntaxException uris)
- {
- throw URLHelper.parseError(uris.getIndex(), uris.getReason(), uris.getInput());
- }
- }
-
-
- private void processOptions()
- {
- // this is where we would parse any options that needed more than just storage.
- }
-
- public String getURL()
- {
- return _url;
- }
-
- public String getExchangeClass()
- {
- return _exchangeClass;
- }
-
- private void setExchangeClass(String exchangeClass)
- {
-
- _exchangeClass = exchangeClass;
- if (exchangeClass.equals(ExchangeDefaults.TOPIC_EXCHANGE_CLASS))
- {
- setOption(BindingURL.OPTION_EXCLUSIVE, "true");
- }
-
- }
-
- public String getExchangeName()
- {
- return _exchangeName;
- }
-
- private void setExchangeName(String name)
- {
- _exchangeName = name;
- }
-
- public String getDestinationName()
- {
- return _destinationName;
- }
-
- private void setDestinationName(String name)
- {
- _destinationName = name;
- }
-
- public String getQueueName()
- {
- return _queueName;
- }
-
- public void setQueueName(String name) throws URLSyntaxException
- {
- if (_exchangeClass.equals(ExchangeDefaults.TOPIC_EXCHANGE_CLASS))
- {
- if (Boolean.parseBoolean(getOption(OPTION_DURABLE)))
- {
- if (containsOption(BindingURL.OPTION_CLIENTID) && containsOption(BindingURL.OPTION_SUBSCRIPTION))
- {
- _queueName = getOption(BindingURL.OPTION_CLIENTID + ":" + BindingURL.OPTION_SUBSCRIPTION);
- }
- else
- {
- throw URLHelper.parseError(-1,
- "Durable subscription must have values for " + BindingURL.OPTION_CLIENTID + " and " + BindingURL.OPTION_SUBSCRIPTION + ".",
- _url);
-
- }
- }
- else
- {
- _queueName = null;
- }
- }
- else
- {
- _queueName = name;
- }
-
- }
-
- public String getOption(String key)
- {
- return _options.get(key);
- }
-
- public void setOption(String key, String value)
- {
- _options.put(key, value);
- }
-
- public boolean containsOption(String key)
- {
- return _options.containsKey(key);
- }
-
- public String getRoutingKey()
- {
- if (_exchangeClass.equals(ExchangeDefaults.DIRECT_EXCHANGE_CLASS))
- {
- return getQueueName();
- }
-
- if (containsOption(BindingURL.OPTION_ROUTING_KEY))
- {
- return getOption(OPTION_ROUTING_KEY);
- }
-
- return getDestinationName();
- }
-
- public void setRoutingKey(String key)
- {
- setOption(OPTION_ROUTING_KEY, key);
- }
-
- public String toString()
- {
- StringBuffer sb = new StringBuffer();
-
- sb.append(_exchangeClass);
- sb.append("://");
- sb.append(_exchangeName);
- sb.append('/');
- sb.append(_destinationName);
- sb.append('/');
- sb.append(_queueName);
-
- sb.append(URLHelper.printOptions(_options));
-
- return sb.toString();
- }
-}
diff --git a/java/common/src/main/java/org/apache/qpid/url/BindingURLParser.java b/java/common/src/main/java/org/apache/qpid/url/BindingURLParser.java
index 5d26e7e65b..7fe7d2e1da 100644
--- a/java/common/src/main/java/org/apache/qpid/url/BindingURLParser.java
+++ b/java/common/src/main/java/org/apache/qpid/url/BindingURLParser.java
@@ -1,4 +1,25 @@
package org.apache.qpid.url;
+/*
+ *
+ * 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.net.URISyntaxException;
import java.util.ArrayList;
@@ -23,7 +44,7 @@ public class BindingURLParser
private static final char COLON_CHAR = ':';
private static final char END_OF_URL_MARKER_CHAR = '%';
- private static final Logger _logger = LoggerFactory.getLogger(BindingURLImpl.class);
+ private static final Logger _logger = LoggerFactory.getLogger(BindingURLParser.class);
private char[] _url;
private AMQBindingURL _bindingURL;
@@ -396,7 +417,7 @@ public class BindingURLParser
{
if (_bindingURL.containsOption(BindingURL.OPTION_CLIENTID) && _bindingURL.containsOption(BindingURL.OPTION_SUBSCRIPTION))
{
- queueName = _bindingURL.getOption(BindingURL.OPTION_CLIENTID + ":" + BindingURL.OPTION_SUBSCRIPTION);
+ queueName = _bindingURL.getOption(BindingURL.OPTION_CLIENTID) + ":" + _bindingURL.getOption(BindingURL.OPTION_SUBSCRIPTION);
}
else
{
diff --git a/java/common/src/main/java/org/apache/qpid/url/QpidBindingURL.java b/java/common/src/main/java/org/apache/qpid/url/QpidBindingURL.java
deleted file mode 100644
index 00edbf1bc3..0000000000
--- a/java/common/src/main/java/org/apache/qpid/url/QpidBindingURL.java
+++ /dev/null
@@ -1,53 +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.url;
-
-import org.apache.qpid.framing.AMQShortString;
-
-/*
- Binding URL format:
- <exch_class>://<exch_name>/[<destination>]/[<queue>]?<option>='<value>'[,<option>='<value>']*
-*/
-public interface QpidBindingURL
-{
- public static final String OPTION_EXCLUSIVE = "exclusive";
- public static final String OPTION_AUTODELETE = "autodelete";
- public static final String OPTION_DURABLE = "durable";
- public static final String OPTION_CLIENTID = "clientid";
- public static final String OPTION_SUBSCRIPTION = "subscription";
- public static final String OPTION_ROUTING_KEY = "routingkey";
-
-
- String getURL();
-
- String getExchangeClass();
-
- String getExchangeName();
-
- String getDestinationName();
-
- String getQueueName();
-
- String getOption(String key);
-
- boolean containsOption(String key);
-
- String getRoutingKey();
-
- String toString();
-}
diff --git a/java/common/src/main/java/org/apache/qpid/url/QpidURL.java b/java/common/src/main/java/org/apache/qpid/url/QpidURL.java
deleted file mode 100644
index 5ab4425323..0000000000
--- a/java/common/src/main/java/org/apache/qpid/url/QpidURL.java
+++ /dev/null
@@ -1,57 +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.url;
-
-import org.apache.qpid.BrokerDetails;
-
-import java.util.List;
-
-/**
- * The format of the Qpid URL is based on the AMQP one.
- * The grammar is as follows:
- * <p> qpid_url = "qpid:" [user_props] prot_addr_list ["/" future-parameters]
- * <p> prot_addr_list = [prot_addr ","]* prot_addr
- * <p> prot_addr = tcp_prot_addr | tls_prot_addr | future_prot_addr
- * <p> tcp_prot_addr = tcp_id tcp_addr
- * <p> tcp_id = "tcp:" | ""
- * <p> tcp_addr = [host [":" port] ]
- * <p> host = <as per [2]>
- * <p> port = number
- * <p> tls_prot_addr = tls_id tls_addr
- * <p> tls_id = "tls:" | ""
- * <p> tls_addr = [host [":" port] ]
- * <p> future_prot_addr = future_prot_id future_prot_addr
- * <p> future_prot_id = <placeholder, must end in ":". Example "sctp:">
- * <p> future_prot_addr = <placeholder, protocl-specific address>
- * <p> future_parameters = <placeholder, not used in failover addresses>
- */
-public interface QpidURL
-{
- /**
- * Get all the broker details
- *
- * @return A list of BrokerDetails.
- */
- public List<BrokerDetails> getAllBrokerDetails();
-
- /**
- * Get this URL string form
- * @return This URL string form.
- */
- public String getURL();
-}
diff --git a/java/common/src/main/java/org/apache/qpid/url/QpidURLImpl.java b/java/common/src/main/java/org/apache/qpid/url/QpidURLImpl.java
deleted file mode 100644
index f92934db7f..0000000000
--- a/java/common/src/main/java/org/apache/qpid/url/QpidURLImpl.java
+++ /dev/null
@@ -1,460 +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.url;
-
-import org.apache.qpid.BrokerDetails;
-import org.apache.qpid.BrokerDetailsImpl;
-
-import java.net.MalformedURLException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * The format Qpid URL is based on the AMQP one.
- * The grammar is as follows:
- * <p> qpid_url = "qpid:" [client_props "@"] port_addr_list ["/" future-parameters]
- * <p> port_addr_list = [port_addr ","]* port_addr
- * <p> port_addr = tcp_port_addr | tls_prot_addr | future_prot_addr
- * <p> tcp_port_addr = tcp_id tcp_addr
- * <p> tcp_id = "tcp:" | ""
- * <p> tcp_addr = host [":" port]
- * <p> host = <as per http://www.apps.ietf.org/>
- * <p> port = number
- * <p> tls_prot_addr = tls_id tls_addr
- * <p> tls_id = "tls:" | ""
- * <p> tls_addr = host [":" port]
- * <p> future_prot_addr = future_prot_id future_prot_addr
- * <p> future_prot_id = <placeholder, must end in ":". Example "sctp:">
- * <p> future_prot_addr = <placeholder, protocl-specific address>
- * <p> future_parameters = <placeholder, not used in failover addresses>
- * <p> client_props = [client_prop ";"]* client_prop
- * <p> client_prop = prop "=" val
- * <p> prop = chars as per <as per http://www.apps.ietf.org/>
- * <p> val = valid as per <as per http://www.apps.ietf.org/>
- * <p/>
- * Ex: qpid:virtualhost=tcp:host-foo,test,client_id=foo@tcp:myhost.com:5672,virtualhost=prod;
- * keystore=/opt/keystore@client_id2@tls:mysecurehost.com:5672
- */
-public class QpidURLImpl implements QpidURL
-{
- private static final char[] URL_START_SEQ = new char[]{'q', 'p', 'i', 'd', ':'};
- private static final char PROPERTY_EQUALS_CHAR = '=';
- private static final char PROPERTY_SEPARATOR_CHAR = ';';
- private static final char ADDRESS_SEPERATOR_CHAR = ',';
-
- //private static final char CLIENT_ID_TRANSPORT_SEPARATOR_CHAR = ':';
- private static final char TRANSPORT_HOST_SEPARATOR_CHAR = ':';
- private static final char HOST_PORT_SEPARATOR_CHAR = ':';
- private static final char AT_CHAR = '@';
-
- enum URLParserState
- {
- QPID_URL_START,
- ADDRESS_START,
- PROPERTY_NAME,
- PROPERTY_EQUALS,
- PROPERTY_VALUE,
- PROPERTY_SEPARATOR,
- AT_CHAR,
- // CLIENT_ID,
- // CLIENT_ID_TRANSPORT_SEPARATOR,
- TRANSPORT,
- TRANSPORT_HOST_SEPARATOR,
- HOST,
- HOST_PORT_SEPARATOR,
- PORT,
- ADDRESS_END,
- ADDRESS_SEPERATOR,
- QPID_URL_END,
- ERROR
- }
-
- //-- Constructors
-
- private char[] _url;
- private List<BrokerDetails> _brokerDetailList = new ArrayList<BrokerDetails>();
- private String _error;
- private int _index = 0;
- private BrokerDetails _currentBroker;
- private String _currentPropName;
- private boolean _endOfURL = false;
- private URLParserState _currentParserState;
-
- public QpidURLImpl(String url) throws MalformedURLException
- {
- _url = url.toCharArray();
- _endOfURL = false;
- _currentParserState = URLParserState.QPID_URL_START;
- URLParserState prevState = _currentParserState; // for error handling
- try
- {
- while (_currentParserState != URLParserState.ERROR && _currentParserState != URLParserState.QPID_URL_END)
- {
- prevState = _currentParserState;
- _currentParserState = next();
- }
-
- if (_currentParserState == URLParserState.ERROR)
- {
- _error =
- "Invalid URL format [current_state = " + prevState + ", broker details parsed so far " + _currentBroker + " ] error at (" + _index + ") due to " + _error;
- MalformedURLException ex;
- ex = new MalformedURLException(_error);
- throw ex;
- }
- }
- catch (ArrayIndexOutOfBoundsException e)
- {
- e.printStackTrace();
- _error =
- "Invalid URL format [current_state = " + prevState + ", broker details parsed so far " + _currentBroker + " ] error at (" + _index + ")";
- MalformedURLException ex;
- ex = new MalformedURLException(_error);
- throw ex;
- }
- }
-
- //-- interface QpidURL
- public List<BrokerDetails> getAllBrokerDetails()
- {
- return _brokerDetailList;
- }
-
- public String getURL()
- {
- return new String(_url);
- }
-
- private URLParserState next()
- {
- switch (_currentParserState)
- {
- case QPID_URL_START:
- return checkSequence(URL_START_SEQ, URLParserState.ADDRESS_START);
- case ADDRESS_START:
- return startAddress();
- case PROPERTY_NAME:
- return extractPropertyName();
- case PROPERTY_EQUALS:
- _index++; // skip the equal sign
- return URLParserState.PROPERTY_VALUE;
- case PROPERTY_VALUE:
- return extractPropertyValue();
- case PROPERTY_SEPARATOR:
- _index++; // skip ","
- return URLParserState.PROPERTY_NAME;
- case AT_CHAR:
- _index++; // skip the @ sign
- return setProperties();
- // case CLIENT_ID:
- // return extractClientId();
- // case CLIENT_ID_TRANSPORT_SEPARATOR:
- // _index++; // skip ":"
- // return URLParserState.TRANSPORT;
- case TRANSPORT:
- return extractTransport();
- case TRANSPORT_HOST_SEPARATOR:
- _index++; // skip ":"
- return URLParserState.HOST;
- case HOST:
- return extractHost();
- case HOST_PORT_SEPARATOR:
- _index++; // skip ":"
- return URLParserState.PORT;
- case PORT:
- return extractPort();
- case ADDRESS_END:
- return endAddress();
- case ADDRESS_SEPERATOR:
- _index++; // skip ","
- return URLParserState.ADDRESS_START;
- default:
- return URLParserState.ERROR;
- }
- }
-
- private URLParserState checkSequence(char[] expected, URLParserState nextPart)
- {
- for (char anExpected : expected)
- {
- if (anExpected != _url[_index])
- {
- _error = "Excepted (" + anExpected + ") at position " + _index + ", got (" + _url[_index] + ")";
- return URLParserState.ERROR;
- }
- _index++;
- }
- return nextPart;
- }
-
- private URLParserState startAddress()
- {
- _currentBroker = new BrokerDetailsImpl();
- // check that there is a "@" before the nexte ","
- for (int j = _index; j < _url.length; j++)
- {
- if (_url[j] == AT_CHAR)
- {
- return URLParserState.PROPERTY_NAME;
- }
- else if (_url[j] == ADDRESS_SEPERATOR_CHAR)
- {
- return URLParserState.TRANSPORT;
- }
- }
- return URLParserState.TRANSPORT;
- }
-
- private URLParserState endAddress()
- {
- _brokerDetailList.add(_currentBroker);
- if (_endOfURL)
- {
- return URLParserState.QPID_URL_END;
- }
- else
- {
- return URLParserState.ADDRESS_SEPERATOR;
- }
- }
-
- private URLParserState extractPropertyName()
- {
- StringBuilder b = new StringBuilder();
- char next = _url[_index];
- while (next != PROPERTY_EQUALS_CHAR && next != AT_CHAR)
- {
- b.append(next);
- next = _url[++_index];
- }
- _currentPropName = b.toString();
- if (_currentPropName.trim().equals(""))
- {
- _error = "Property name cannot be empty";
- return URLParserState.ERROR;
- }
- else if (next == PROPERTY_EQUALS_CHAR)
- {
- return URLParserState.PROPERTY_EQUALS;
- }
- else
- {
- return URLParserState.AT_CHAR;
- }
- }
-
- private URLParserState extractPropertyValue()
- {
- StringBuilder b = new StringBuilder();
- char next = _url[_index];
- while (next != PROPERTY_SEPARATOR_CHAR && next != AT_CHAR)
- {
- b.append(next);
- next = _url[++_index];
- }
- String propValue = b.toString();
- if (propValue.trim().equals(""))
- {
- _error = "Property values cannot be empty";
- return URLParserState.ERROR;
- }
- else
- {
- _currentBroker.setProperty(_currentPropName, propValue);
- if (next == PROPERTY_SEPARATOR_CHAR)
- {
- return URLParserState.PROPERTY_SEPARATOR;
- }
- else
- {
- return URLParserState.AT_CHAR;
- }
- }
- }
-
- private URLParserState setProperties()
- {
- //Check if atleast virtualhost is there
- if (_currentBroker.getProperties().get(BrokerDetails.VIRTUAL_HOST) != null)
- {
- _currentBroker.setVirtualHost(_currentBroker.getProperties().get(BrokerDetails.VIRTUAL_HOST));
- _currentBroker.getProperties().remove(BrokerDetails.VIRTUAL_HOST);
- }
-
- if (_currentBroker.getProperties().get(BrokerDetails.USERNAME) != null)
- {
- String username = _currentBroker.getProperties().get(BrokerDetails.USERNAME);
- _currentBroker.setUserName(username);
- }
- if (_currentBroker.getProperties().get(BrokerDetails.PASSWORD) != null)
- {
- String password = _currentBroker.getProperties().get(BrokerDetails.PASSWORD);
- _currentBroker.setPassword(password);
- }
- if (_currentBroker.getProperties().get(BrokerDetails.CLIENT_ID) != null)
- {
- String clientID = _currentBroker.getProperties().get(BrokerDetails.CLIENT_ID);
- _currentBroker.setProperty(BrokerDetails.CLIENT_ID, clientID);
- }
- return URLParserState.TRANSPORT;
- }
-
- private URLParserState extractTransport()
- {
- String transport = buildUntil(TRANSPORT_HOST_SEPARATOR_CHAR);
- if (transport.trim().equals(""))
- {
- _error = "Transport cannot be empty";
- return URLParserState.ERROR;
- }
- else if (!(transport.trim().equals(BrokerDetails.PROTOCOL_TCP) || transport.trim()
- .equals(BrokerDetails.PROTOCOL_TLS)))
- {
- _error = "Transport cannot be " + transport + " value must be tcp or tls";
- return URLParserState.ERROR;
- }
- else
- {
- _currentBroker.setProtocol(transport);
- return URLParserState.TRANSPORT_HOST_SEPARATOR;
- }
- }
-
- private URLParserState extractHost()
- {
- char nextSep = 'c';
- String host;
- for (int i = _index; i < _url.length; i++)
- {
- if (_url[i] == HOST_PORT_SEPARATOR_CHAR)
- {
- nextSep = HOST_PORT_SEPARATOR_CHAR;
- break;
- }
- else if (_url[i] == ADDRESS_SEPERATOR_CHAR)
- {
- nextSep = ADDRESS_SEPERATOR_CHAR;
- break;
- }
- }
- if (nextSep == HOST_PORT_SEPARATOR_CHAR)
- {
- host = buildUntil(HOST_PORT_SEPARATOR_CHAR);
- if (host.trim().equals(""))
- {
- _error = "Host cannot be empty";
- return URLParserState.ERROR;
- }
- else
- {
- _currentBroker.setHost(host);
- return URLParserState.HOST_PORT_SEPARATOR;
- }
- }
- else if (nextSep == ADDRESS_SEPERATOR_CHAR)
- {
- host = buildUntil(ADDRESS_SEPERATOR_CHAR);
- if (host.trim().equals(""))
- {
- _error = "Host cannot be empty";
- return URLParserState.ERROR;
- }
- else
- {
- _currentBroker.setHost(host);
- return URLParserState.ADDRESS_END;
- }
- }
- else
- {
- host = String.copyValueOf(_url, _index, _url.length - _index);
- _currentBroker.setHost(host);
- _endOfURL = true;
- return URLParserState.ADDRESS_END;
- }
- }
-
-
- private URLParserState extractPort()
- {
-
- StringBuilder b = new StringBuilder();
- try
- {
- char next = _url[_index];
- while (next != ADDRESS_SEPERATOR_CHAR)
- {
- b.append(next);
- next = _url[++_index];
- }
- }
- catch (ArrayIndexOutOfBoundsException e)
- {
- _endOfURL = true;
- }
- String portStr = b.toString();
- if (portStr.trim().equals(""))
- {
- _error = "Host cannot be empty";
- return URLParserState.ERROR;
- }
- else
- {
- try
- {
- int port = Integer.parseInt(portStr);
- _currentBroker.setPort(port);
- return URLParserState.ADDRESS_END;
- }
- catch (NumberFormatException e)
- {
- _error = "Illegal number for port";
- return URLParserState.ERROR;
- }
- }
- }
-
- private String buildUntil(char c)
- {
- StringBuilder b = new StringBuilder();
- char next = _url[_index];
- while (next != c)
- {
- b.append(next);
- next = _url[++_index];
- }
- return b.toString();
- }
-
- public static void main(String[] args)
- {
- String testurl = "qpid:password=pass;username=name@tcp:test1,tcp:fooBroker,keystore=/usr/foo@tls:tlsBroker";
- try
- {
- QpidURLImpl impl = new QpidURLImpl(testurl);
- for (BrokerDetails d : impl.getAllBrokerDetails())
- {
- System.out.println(d);
- }
- }
- catch (Exception e)
- {
- e.printStackTrace();
- }
- }
-}
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 7494745457..7ba38f4743 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
@@ -20,7 +20,18 @@
*/
package org.apache.qpid.util;
-import java.io.*;
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.LinkedList;
+import java.util.List;
/**
* FileUtils provides some simple helper methods for working with files. It follows the convention of wrapping all
@@ -48,14 +59,31 @@ public class FileUtils
try
{
- is = new BufferedInputStream(new FileInputStream(filename));
+ try
+ {
+ is = new BufferedInputStream(new FileInputStream(filename));
+ }
+ catch (FileNotFoundException e)
+ {
+ throw new RuntimeException(e);
+ }
+
+ return readStreamAsString(is);
}
- catch (FileNotFoundException e)
+ finally
{
- throw new RuntimeException(e);
+ if (is != null)
+ {
+ try
+ {
+ is.close();
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
}
-
- return readStreamAsString(is);
}
/**
@@ -168,28 +196,182 @@ public class FileUtils
{
try
{
- InputStream in = new FileInputStream(src);
- if (!dst.exists())
+ copyCheckedEx(src, dst);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Copies the specified source file to the specified destination file. If the destination file does not exist,
+ * it is created.
+ *
+ * @param src The source file name.
+ * @param dst The destination file name.
+ * @throws IOException
+ */
+ public static void copyCheckedEx(File src, File dst) throws IOException
+ {
+ InputStream in = new FileInputStream(src);
+ if (!dst.exists())
+ {
+ dst.createNewFile();
+ }
+
+ OutputStream out = new FileOutputStream(dst);
+
+ // Transfer bytes from in to out
+ byte[] buf = new byte[1024];
+ int len;
+ while ((len = in.read(buf)) > 0)
+ {
+ out.write(buf, 0, len);
+ }
+
+ in.close();
+ out.close();
+ }
+
+ /*
+ * Deletes a given file
+ */
+ public static boolean deleteFile(String filePath)
+ {
+ return delete(new File(filePath), false);
+ }
+
+ /*
+ * Deletes a given empty directory
+ */
+ public static boolean deleteDirectory(String directoryPath)
+ {
+ File directory = new File(directoryPath);
+
+ if (directory.isDirectory())
+ {
+ if (directory.listFiles().length == 0)
{
- dst.createNewFile();
+ return delete(directory, true);
}
+ }
- OutputStream out = new FileOutputStream(dst);
+ return false;
+ }
- // Transfer bytes from in to out
- byte[] buf = new byte[1024];
- int len;
- while ((len = in.read(buf)) > 0)
+ /**
+ * Delete a given file/directory,
+ * A directory will always require the recursive flag to be set.
+ * if a directory is specified and recursive set then delete the whole tree
+ *
+ * @param file the File object to start at
+ * @param recursive boolean to recurse if a directory is specified.
+ *
+ * @return <code>true</code> if and only if the file or directory is
+ * successfully deleted; <code>false</code> otherwise
+ */
+ public static boolean delete(File file, boolean recursive)
+ {
+ boolean success = true;
+
+ if (file.isDirectory())
+ {
+ if (recursive)
{
- out.write(buf, 0, len);
+ File[] files = file.listFiles();
+
+ // This can occur if the file is deleted outside the JVM
+ if (files == null)
+ {
+ return false;
+ }
+
+ for (int i = 0; i < files.length; i++)
+ {
+ success = delete(files[i], true) && success;
+ }
+
+ return success && file.delete();
}
- in.close();
- out.close();
+ return false;
}
- catch (IOException e)
+
+ return file.delete();
+ }
+
+ public static class UnableToCopyException extends Exception
+ {
+ UnableToCopyException(String msg)
{
- throw new RuntimeException(e);
+ super(msg);
}
}
+
+ public static void copyRecursive(File source, File dst) throws FileNotFoundException, UnableToCopyException
+ {
+
+ if (!source.exists())
+ {
+ throw new FileNotFoundException("Unable to copy '" + source.toString() + "' as it does not exist.");
+ }
+
+ if (dst.exists() && !dst.isDirectory())
+ {
+ throw new IllegalArgumentException("Unable to copy '" + source.toString() + "' to '" + dst + "' a file with same name exists.");
+ }
+
+ if (source.isFile())
+ {
+ copy(source, dst);
+ }
+
+ //else we have a source directory
+ if (!dst.isDirectory() && !dst.mkdir())
+ {
+ throw new UnableToCopyException("Unable to create destination directory");
+ }
+
+ for (File file : source.listFiles())
+ {
+ if (file.isFile())
+ {
+ copy(file, new File(dst.toString() + File.separator + file.getName()));
+ }
+ else
+ {
+ copyRecursive(file, new File(dst + File.separator + file.getName()));
+ }
+ }
+
+ }
+
+ /**
+ * Checks the specified file for instances of the search string.
+ *
+ * @param file the file to search
+ * @param search the search String
+ *
+ * @throws java.io.IOException
+ * @return the list of matching entries
+ */
+ public static List<String> searchFile(File file, String search)
+ throws IOException
+ {
+
+ List<String> results = new LinkedList<String>();
+
+ BufferedReader reader = new BufferedReader(new FileReader(file));
+ while (reader.ready())
+ {
+ String line = reader.readLine();
+ if (line.contains(search))
+ {
+ results.add(line);
+ }
+ }
+
+ return results;
+ }
}
diff --git a/java/common/src/main/java/org/apache/qpid/util/NetMatcher.java b/java/common/src/main/java/org/apache/qpid/util/NetMatcher.java
new file mode 100644
index 0000000000..4c653e6ca0
--- /dev/null
+++ b/java/common/src/main/java/org/apache/qpid/util/NetMatcher.java
@@ -0,0 +1,264 @@
+/***********************************************************************
+ * Copyright (c) 2000-2006 The Apache Software Foundation. *
+ * All rights reserved. *
+ * ------------------------------------------------------------------- *
+ * 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.qpid.util;
+
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+
+public class NetMatcher
+{
+ private ArrayList networks;
+
+ public void initInetNetworks(final Collection nets)
+ {
+ networks = new ArrayList();
+ for (Iterator iter = nets.iterator(); iter.hasNext(); ) try
+ {
+ InetNetwork net = InetNetwork.getFromString((String) iter.next());
+ if (!networks.contains(net)) networks.add(net);
+ }
+ catch (java.net.UnknownHostException uhe)
+ {
+ log("Cannot resolve address: " + uhe.getMessage());
+ }
+ networks.trimToSize();
+ }
+
+ public void initInetNetworks(final String[] nets)
+ {
+ networks = new ArrayList();
+ for (int i = 0; i < nets.length; i++) try
+ {
+ InetNetwork net = InetNetwork.getFromString(nets[i]);
+ if (!networks.contains(net)) networks.add(net);
+ }
+ catch (java.net.UnknownHostException uhe)
+ {
+ log("Cannot resolve address: " + uhe.getMessage());
+ }
+ networks.trimToSize();
+ }
+
+ public boolean matchInetNetwork(final String hostIP)
+ {
+ InetAddress ip = null;
+
+ try
+ {
+ ip = InetAddress.getByName(hostIP);
+ }
+ catch (java.net.UnknownHostException uhe)
+ {
+ log("Cannot resolve address for " + hostIP + ": " + uhe.getMessage());
+ }
+
+ boolean sameNet = false;
+
+ if (ip != null) for (Iterator iter = networks.iterator(); (!sameNet) && iter.hasNext(); )
+ {
+ InetNetwork network = (InetNetwork) iter.next();
+ sameNet = network.contains(ip);
+ }
+ return sameNet;
+ }
+
+ public boolean matchInetNetwork(final InetAddress ip)
+ {
+ boolean sameNet = false;
+
+ for (Iterator iter = networks.iterator(); (!sameNet) && iter.hasNext(); )
+ {
+ InetNetwork network = (InetNetwork) iter.next();
+ sameNet = network.contains(ip);
+ }
+ return sameNet;
+ }
+
+ public NetMatcher()
+ {
+ }
+
+ public NetMatcher(final String[] nets)
+ {
+ initInetNetworks(nets);
+ }
+
+ public NetMatcher(final Collection nets)
+ {
+ initInetNetworks(nets);
+ }
+
+ public String toString() {
+ return networks.toString();
+ }
+
+ protected void log(String s) { }
+}
+
+class InetNetwork
+{
+ /*
+ * Implements network masking, and is compatible with RFC 1518 and
+ * RFC 1519, which describe CIDR: Classless Inter-Domain Routing.
+ */
+
+ private InetAddress network;
+ private InetAddress netmask;
+
+ public InetNetwork(InetAddress ip, InetAddress netmask)
+ {
+ network = maskIP(ip, netmask);
+ this.netmask = netmask;
+ }
+
+ public boolean contains(final String name) throws java.net.UnknownHostException
+ {
+ return network.equals(maskIP(InetAddress.getByName(name), netmask));
+ }
+
+ public boolean contains(final InetAddress ip)
+ {
+ return network.equals(maskIP(ip, netmask));
+ }
+
+ public String toString()
+ {
+ return network.getHostAddress() + "/" + netmask.getHostAddress();
+ }
+
+ public int hashCode()
+ {
+ return maskIP(network, netmask).hashCode();
+ }
+
+ public boolean equals(Object obj)
+ {
+ return (obj != null) && (obj instanceof InetNetwork) &&
+ ((((InetNetwork)obj).network.equals(network)) && (((InetNetwork)obj).netmask.equals(netmask)));
+ }
+
+ public static InetNetwork getFromString(String netspec) throws java.net.UnknownHostException
+ {
+ if (netspec.endsWith("*")) netspec = normalizeFromAsterisk(netspec);
+ else
+ {
+ int iSlash = netspec.indexOf('/');
+ if (iSlash == -1) netspec += "/255.255.255.255";
+ else if (netspec.indexOf('.', iSlash) == -1) netspec = normalizeFromCIDR(netspec);
+ }
+
+ return new InetNetwork(InetAddress.getByName(netspec.substring(0, netspec.indexOf('/'))),
+ InetAddress.getByName(netspec.substring(netspec.indexOf('/') + 1)));
+ }
+
+ public static InetAddress maskIP(final byte[] ip, final byte[] mask)
+ {
+ try
+ {
+ return getByAddress(new byte[]
+ {
+ (byte) (mask[0] & ip[0]),
+ (byte) (mask[1] & ip[1]),
+ (byte) (mask[2] & ip[2]),
+ (byte) (mask[3] & ip[3])
+ });
+ }
+ catch(Exception _) {}
+ {
+ return null;
+ }
+ }
+
+ public static InetAddress maskIP(final InetAddress ip, final InetAddress mask)
+ {
+ return maskIP(ip.getAddress(), mask.getAddress());
+ }
+
+ /*
+ * This converts from an uncommon "wildcard" CIDR format
+ * to "address + mask" format:
+ *
+ * * => 000.000.000.0/000.000.000.0
+ * xxx.* => xxx.000.000.0/255.000.000.0
+ * xxx.xxx.* => xxx.xxx.000.0/255.255.000.0
+ * xxx.xxx.xxx.* => xxx.xxx.xxx.0/255.255.255.0
+ */
+ static private String normalizeFromAsterisk(final String netspec)
+ {
+ String[] masks = { "0.0.0.0/0.0.0.0", "0.0.0/255.0.0.0", "0.0/255.255.0.0", "0/255.255.255.0" };
+ char[] srcb = netspec.toCharArray();
+ int octets = 0;
+ for (int i = 1; i < netspec.length(); i++) {
+ if (srcb[i] == '.') octets++;
+ }
+ return (octets == 0) ? masks[0] : netspec.substring(0, netspec.length() -1 ).concat(masks[octets]);
+ }
+
+ /*
+ * RFC 1518, 1519 - Classless Inter-Domain Routing (CIDR)
+ * This converts from "prefix + prefix-length" format to
+ * "address + mask" format, e.g. from xxx.xxx.xxx.xxx/yy
+ * to xxx.xxx.xxx.xxx/yyy.yyy.yyy.yyy.
+ */
+ static private String normalizeFromCIDR(final String netspec)
+ {
+ final int bits = 32 - Integer.parseInt(netspec.substring(netspec.indexOf('/')+1));
+ final int mask = (bits == 32) ? 0 : 0xFFFFFFFF - ((1 << bits)-1);
+
+ return netspec.substring(0, netspec.indexOf('/') + 1) +
+ Integer.toString(mask >> 24 & 0xFF, 10) + "." +
+ Integer.toString(mask >> 16 & 0xFF, 10) + "." +
+ Integer.toString(mask >> 8 & 0xFF, 10) + "." +
+ Integer.toString(mask >> 0 & 0xFF, 10);
+ }
+
+ private static java.lang.reflect.Method getByAddress = null;
+
+ static {
+ try {
+ Class inetAddressClass = Class.forName("java.net.InetAddress");
+ Class[] parameterTypes = { byte[].class };
+ getByAddress = inetAddressClass.getMethod("getByAddress", parameterTypes);
+ } catch (Exception e) {
+ getByAddress = null;
+ }
+ }
+
+ private static InetAddress getByAddress(byte[] ip) throws java.net.UnknownHostException
+ {
+ InetAddress addr = null;
+ if (getByAddress != null) try {
+ addr = (InetAddress) getByAddress.invoke(null, new Object[] { ip });
+ } catch (IllegalAccessException e) {
+ } catch (java.lang.reflect.InvocationTargetException e) {
+ }
+
+ if (addr == null) {
+ addr = InetAddress.getByName
+ (
+ Integer.toString(ip[0] & 0xFF, 10) + "." +
+ Integer.toString(ip[1] & 0xFF, 10) + "." +
+ Integer.toString(ip[2] & 0xFF, 10) + "." +
+ Integer.toString(ip[3] & 0xFF, 10)
+ );
+ }
+ return addr;
+ }
+}
diff --git a/java/common/src/main/java/org/apache/qpid/util/PropertiesUtils.java b/java/common/src/main/java/org/apache/qpid/util/PropertiesUtils.java
deleted file mode 100644
index d90e3b1a17..0000000000
--- a/java/common/src/main/java/org/apache/qpid/util/PropertiesUtils.java
+++ /dev/null
@@ -1,200 +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.util;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.net.URL;
-import java.util.Iterator;
-import java.util.Properties;
-
-/**
- * PropertiesHelper defines some static methods which are useful when working with properties
- * files.
- *
- * <p><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Read properties from an input stream
- * <tr><td> Read properties from a file
- * <tr><td> Read properties from a URL
- * <tr><td> Read properties given a path to a file
- * <tr><td> Trim any whitespace from property values
- * </table>
- */
-public class PropertiesUtils
-{
- /** Used for logging. */
- private static final Logger log = LoggerFactory.getLogger(PropertiesUtils.class);
-
- /**
- * Get properties from an input stream.
- *
- * @param is The input stream.
- *
- * @return The properties loaded from the input stream.
- *
- * @throws IOException If the is an I/O error reading from the stream.
- */
- public static Properties getProperties(InputStream is) throws IOException
- {
- log.debug("getProperties(InputStream): called");
-
- // Create properties object laoded from input stream
- Properties properties = new Properties();
-
- properties.load(is);
-
- return properties;
- }
-
- /**
- * Get properties from a file.
- *
- * @param file The file.
- *
- * @return The properties loaded from the file.
- *
- * @throws IOException If there is an I/O error reading from the file.
- */
- public static Properties getProperties(File file) throws IOException
- {
- log.debug("getProperties(File): called");
-
- // Open the file as an input stream
- InputStream is = new FileInputStream(file);
-
- // Create properties object loaded from the stream
- Properties properties = getProperties(is);
-
- // Close the file
- is.close();
-
- return properties;
- }
-
- /**
- * Get properties from a url.
- *
- * @param url The URL.
- *
- * @return The properties loaded from the url.
- *
- * @throws IOException If there is an I/O error reading from the URL.
- */
- public static Properties getProperties(URL url) throws IOException
- {
- log.debug("getProperties(URL): called");
-
- // Open the URL as an input stream
- InputStream is = url.openStream();
-
- // Create properties object loaded from the stream
- Properties properties = getProperties(is);
-
- // Close the url
- is.close();
-
- return properties;
- }
-
- /**
- * Get properties from a path name. The path name may refer to either a file or a URL.
- *
- * @param pathname The path name.
- *
- * @return The properties loaded from the file or URL.
- *
- * @throws IOException If there is an I/O error reading from the URL or file named by the path.
- */
- public static Properties getProperties(String pathname) throws IOException
- {
- log.debug("getProperties(String): called");
-
- // Check that the path is not null
- if (pathname == null)
- {
- return null;
- }
-
- // Check if the path is a URL
- if (isURL(pathname))
- {
- // The path is a URL
- return getProperties(new URL(pathname));
- }
- else
- {
- // Assume the path is a file name
- return getProperties(new File(pathname));
- }
- }
-
- /**
- * Trims whitespace from property values. This method returns a new set of properties
- * the same as the properties specified as an argument but with any white space removed by
- * the {@link java.lang.String#trim} method.
- *
- * @param properties The properties to trim whitespace from.
- *
- * @return The white space trimmed properties.
- */
- public static Properties trim(Properties properties)
- {
- Properties trimmedProperties = new Properties();
-
- // Loop over all the properties
- for (Iterator i = properties.keySet().iterator(); i.hasNext();)
- {
- String next = (String) i.next();
- String nextValue = properties.getProperty(next);
-
- // Trim the value if it is not null
- if (nextValue != null)
- {
- nextValue.trim();
- }
-
- // Store the trimmed value in the trimmed properties
- trimmedProperties.setProperty(next, nextValue);
- }
-
- return trimmedProperties;
- }
-
- /**
- * Helper method. Guesses whether a string is a URL or not. A String is considered to be a url if it begins with
- * http:, ftp:, or uucp:.
- *
- * @param name The string to test for being a URL.
- *
- * @return True if the string is a URL and false if not.
- */
- private static boolean isURL(String name)
- {
- return (name.toLowerCase().startsWith("http:") || name.toLowerCase().startsWith("ftp:")
- || name.toLowerCase().startsWith("uucp:"));
- }
-}
diff --git a/java/common/src/main/java/org/apache/qpid/util/Serial.java b/java/common/src/main/java/org/apache/qpid/util/Serial.java
index 44712984c0..8ad9d00f54 100644
--- a/java/common/src/main/java/org/apache/qpid/util/Serial.java
+++ b/java/common/src/main/java/org/apache/qpid/util/Serial.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util;
+/*
+ *
+ * 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.Comparator;
diff --git a/java/common/src/main/java/org/apache/qpid/util/Strings.java b/java/common/src/main/java/org/apache/qpid/util/Strings.java
index 4b199bafe6..04bf174ff0 100644
--- a/java/common/src/main/java/org/apache/qpid/util/Strings.java
+++ b/java/common/src/main/java/org/apache/qpid/util/Strings.java
@@ -22,6 +22,12 @@ package org.apache.qpid.util;
import java.io.UnsupportedEncodingException;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Stack;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
/**
* Strings
@@ -79,4 +85,154 @@ public final class Strings
}
}
+ public static final String fromUTF8(byte[] bytes)
+ {
+ try
+ {
+ return new String(bytes, "UTF-8");
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static final Pattern VAR = Pattern.compile("(?:\\$\\{([^\\}]*)\\})|(?:\\$(\\$))");
+
+ public static interface Resolver
+ {
+ String resolve(String variable);
+ }
+
+ public static class MapResolver implements Resolver
+ {
+
+ private final Map<String,String> map;
+
+ public MapResolver(Map<String,String> map)
+ {
+ this.map = map;
+ }
+
+ public String resolve(String variable)
+ {
+ return map.get(variable);
+ }
+ }
+
+ public static class PropertiesResolver implements Resolver
+ {
+
+ private final Properties properties;
+
+ public PropertiesResolver(Properties properties)
+ {
+ this.properties = properties;
+ }
+
+ public String resolve(String variable)
+ {
+ return properties.getProperty(variable);
+ }
+ }
+
+ public static class ChainedResolver implements Resolver
+ {
+ private final Resolver primary;
+ private final Resolver secondary;
+
+ public ChainedResolver(Resolver primary, Resolver secondary)
+ {
+ this.primary = primary;
+ this.secondary = secondary;
+ }
+
+ public String resolve(String variable)
+ {
+ String result = primary.resolve(variable);
+ if (result == null)
+ {
+ result = secondary.resolve(variable);
+ }
+ return result;
+ }
+ }
+
+ public static final Resolver SYSTEM_RESOLVER = new Resolver()
+ {
+ public String resolve(String variable)
+ {
+ String result = System.getProperty(variable);
+ if (result == null)
+ {
+ result = System.getenv(variable);
+ }
+ return result;
+ }
+ };
+
+ public static final String expand(String input)
+ {
+ return expand(input, SYSTEM_RESOLVER);
+ }
+
+ public static final String expand(String input, Resolver resolver)
+ {
+ return expand(input, resolver, new Stack());
+ }
+
+ private static final String expand(String input, Resolver resolver, Stack<String> stack)
+ {
+ Matcher m = VAR.matcher(input);
+ StringBuffer result = new StringBuffer();
+ while (m.find())
+ {
+ String var = m.group(1);
+ if (var == null)
+ {
+ String esc = m.group(2);
+ if ("$".equals(esc))
+ {
+ m.appendReplacement(result, Matcher.quoteReplacement("$"));
+ }
+ else
+ {
+ throw new IllegalArgumentException(esc);
+ }
+ }
+ else
+ {
+ m.appendReplacement(result, Matcher.quoteReplacement(resolve(var, resolver, stack)));
+ }
+ }
+ m.appendTail(result);
+ return result.toString();
+ }
+
+ private static final String resolve(String var, Resolver resolver, Stack<String> stack)
+ {
+ if (stack.contains(var))
+ {
+ throw new IllegalArgumentException
+ (String.format("recursively defined variable: %s stack=%s", var,
+ stack));
+ }
+
+ String result = resolver.resolve(var);
+ if (result == null)
+ {
+ throw new IllegalArgumentException("no such variable: " + var);
+ }
+
+ stack.push(var);
+ try
+ {
+ return expand(result, resolver, stack);
+ }
+ finally
+ {
+ stack.pop();
+ }
+ }
+
}
diff --git a/java/common/src/main/java/org/apache/qpid/util/concurrent/AlreadyUnblockedException.java b/java/common/src/main/java/org/apache/qpid/util/concurrent/AlreadyUnblockedException.java
index ef43d1c8a8..e0c0337898 100644
--- a/java/common/src/main/java/org/apache/qpid/util/concurrent/AlreadyUnblockedException.java
+++ b/java/common/src/main/java/org/apache/qpid/util/concurrent/AlreadyUnblockedException.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util.concurrent;
+/*
+ *
+ * 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.
+ *
+ */
+
/**
* Used to signal that a data element and its producer cannot be requeued or sent an error message when using a
diff --git a/java/common/src/main/java/org/apache/qpid/util/concurrent/BatchSynchQueue.java b/java/common/src/main/java/org/apache/qpid/util/concurrent/BatchSynchQueue.java
index 261eecb561..63d8f77edb 100644
--- a/java/common/src/main/java/org/apache/qpid/util/concurrent/BatchSynchQueue.java
+++ b/java/common/src/main/java/org/apache/qpid/util/concurrent/BatchSynchQueue.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util.concurrent;
+/*
+ *
+ * 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.Collection;
import java.util.concurrent.BlockingQueue;
diff --git a/java/common/src/main/java/org/apache/qpid/util/concurrent/BatchSynchQueueBase.java b/java/common/src/main/java/org/apache/qpid/util/concurrent/BatchSynchQueueBase.java
index d1c1abd285..4564b1d686 100644
--- a/java/common/src/main/java/org/apache/qpid/util/concurrent/BatchSynchQueueBase.java
+++ b/java/common/src/main/java/org/apache/qpid/util/concurrent/BatchSynchQueueBase.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util.concurrent;
+/*
+ *
+ * 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.*;
import java.util.concurrent.TimeUnit;
diff --git a/java/common/src/main/java/org/apache/qpid/util/concurrent/BooleanLatch.java b/java/common/src/main/java/org/apache/qpid/util/concurrent/BooleanLatch.java
index 391ca686c9..0e4a07594f 100644
--- a/java/common/src/main/java/org/apache/qpid/util/concurrent/BooleanLatch.java
+++ b/java/common/src/main/java/org/apache/qpid/util/concurrent/BooleanLatch.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util.concurrent;
+/*
+ *
+ * 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.concurrent.locks.AbstractQueuedSynchronizer;
diff --git a/java/common/src/main/java/org/apache/qpid/util/concurrent/Capacity.java b/java/common/src/main/java/org/apache/qpid/util/concurrent/Capacity.java
index e317c84971..a97ce0e172 100644
--- a/java/common/src/main/java/org/apache/qpid/util/concurrent/Capacity.java
+++ b/java/common/src/main/java/org/apache/qpid/util/concurrent/Capacity.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util.concurrent;
+/*
+ *
+ * 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.
+ *
+ */
+
/**
* An interface exposed by data structures that have a maximum capacity.
diff --git a/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchBuffer.java b/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchBuffer.java
index 49020803d7..bc63eb0353 100644
--- a/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchBuffer.java
+++ b/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchBuffer.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util.concurrent;
+/*
+ *
+ * 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.Queue;
diff --git a/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchException.java b/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchException.java
index 77b60f2b72..99a83f96cd 100644
--- a/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchException.java
+++ b/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchException.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util.concurrent;
+/*
+ *
+ * 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.
+ *
+ */
+
/**
* SynchException is used to encapsulate exceptions with the data elements that caused them in order to send exceptions
diff --git a/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchQueue.java b/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchQueue.java
index 9d15c211f6..95833f398a 100644
--- a/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchQueue.java
+++ b/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchQueue.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util.concurrent;
+/*
+ *
+ * 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.LinkedList;
import java.util.Queue;
diff --git a/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchRecord.java b/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchRecord.java
index 5e002100c2..fd740c20cd 100644
--- a/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchRecord.java
+++ b/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchRecord.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util.concurrent;
+/*
+ *
+ * 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.
+ *
+ */
+
/**
* SynchRecord associates a data item from a {@link BatchSynchQueue} with its producer. This enables the data item data
diff --git a/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchRef.java b/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchRef.java
index a75f7b766d..efe2344c06 100644
--- a/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchRef.java
+++ b/java/common/src/main/java/org/apache/qpid/util/concurrent/SynchRef.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util.concurrent;
+/*
+ *
+ * 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.
+ *
+ */
+
/**
* A SynchRef is an interface which is returned from the synchronous take and drain methods of {@link BatchSynchQueue},
diff --git a/java/common/src/test/java/org/apache/qpid/AMQExceptionTest.java b/java/common/src/test/java/org/apache/qpid/AMQExceptionTest.java
new file mode 100644
index 0000000000..ef6cd41492
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/AMQExceptionTest.java
@@ -0,0 +1,106 @@
+/*
+ *
+ * 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 junit.framework.TestCase;
+import org.apache.qpid.protocol.AMQConstant;
+import org.apache.qpid.framing.AMQFrameDecodingException;
+
+/**
+ * This test is to ensure that when an AMQException is rethrown that the specified exception is correctly wrapped up.
+ *
+ * There are three cases:
+ * Re-throwing an AMQException
+ * Re-throwing a Subclass of AMQException
+ * Re-throwing a Subclass of AMQException that does not have the default AMQException constructor which will force the
+ * creation of an AMQException.
+ */
+public class AMQExceptionTest extends TestCase
+{
+ /**
+ * Test that an AMQException will be correctly created and rethrown.
+ */
+ public void testRethrowGeneric()
+ {
+ AMQException test = new AMQException(AMQConstant.ACCESS_REFUSED, "refused", new RuntimeException());
+
+ AMQException e = reThrowException(test);
+
+ assertEquals("Exception not of correct class", AMQException.class, e.getClass());
+
+ }
+
+ /**
+ * Test that a subclass of AMQException that has the default constructor will be correctly created and rethrown.
+ */
+ public void testRethrowAMQESubclass()
+ {
+ AMQFrameDecodingException test = new AMQFrameDecodingException(AMQConstant.INTERNAL_ERROR,
+ "Error",
+ new Exception());
+ AMQException e = reThrowException(test);
+
+ assertEquals("Exception not of correct class", AMQFrameDecodingException.class, e.getClass());
+ }
+
+ /**
+ * Test that a subclass of AMQException that doesnot have the default constructor will be correctly rethrown as an
+ * AMQException
+ */
+ public void testRethrowAMQESubclassNoConstructor()
+ {
+ AMQExceptionSubclass test = new AMQExceptionSubclass("Invalid Argument Exception");
+
+ AMQException e = reThrowException(test);
+
+ assertEquals("Exception not of correct class", AMQException.class, e.getClass());
+ }
+
+ /**
+ * Private method to rethrown and validate the basic values of the rethrown
+ * @param test Exception to rethrow
+ * @throws AMQException the rethrown exception
+ */
+ private AMQException reThrowException(AMQException test)
+ {
+ AMQException amqe = test.cloneForCurrentThread();
+
+ assertEquals("Error code does not match.", test.getErrorCode(), amqe.getErrorCode());
+ assertTrue("Exception message does not start as expected.", amqe.getMessage().startsWith(test.getMessage()));
+ assertEquals("Test Exception is not set as the cause", test, amqe.getCause());
+ assertEquals("Cause is not correct", test.getCause(), amqe.getCause().getCause());
+
+ return amqe;
+ }
+
+ /**
+ * Private class that extends AMQException but does not have a default exception.
+ */
+ private class AMQExceptionSubclass extends AMQException
+ {
+
+ public AMQExceptionSubclass(String msg)
+ {
+ super(null, msg, null);
+ }
+ }
+}
+
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
new file mode 100644
index 0000000000..46c812e265
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/codec/AMQDecoderTest.java
@@ -0,0 +1,130 @@
+package org.apache.qpid.codec;
+
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+
+import junit.framework.TestCase;
+
+import org.apache.qpid.framing.AMQDataBlock;
+import org.apache.qpid.framing.AMQFrame;
+import org.apache.qpid.framing.AMQFrameDecodingException;
+import org.apache.qpid.framing.AMQProtocolVersionException;
+import org.apache.qpid.framing.HeartbeatBody;
+
+public class AMQDecoderTest extends TestCase
+{
+
+ private AMQCodecFactory _factory;
+ private AMQDecoder _decoder;
+
+
+ public void setUp()
+ {
+ _factory = new AMQCodecFactory(false, null);
+ _decoder = _factory.getDecoder();
+ }
+
+
+ public void testSingleFrameDecode() throws AMQProtocolVersionException, AMQFrameDecodingException
+ {
+ ByteBuffer msg = HeartbeatBody.FRAME.toNioByteBuffer();
+ ArrayList<AMQDataBlock> frames = _decoder.decodeBuffer(msg);
+ if (frames.get(0) instanceof AMQFrame)
+ {
+ assertEquals(HeartbeatBody.FRAME.getBodyFrame().getFrameType(), ((AMQFrame) frames.get(0)).getBodyFrame().getFrameType());
+ }
+ else
+ {
+ fail("decode was not a frame");
+ }
+ }
+
+ public void testPartialFrameDecode() throws AMQProtocolVersionException, AMQFrameDecodingException
+ {
+ ByteBuffer msg = HeartbeatBody.FRAME.toNioByteBuffer();
+ ByteBuffer msgA = msg.slice();
+ int msgbPos = msg.remaining() / 2;
+ int msgaLimit = msg.remaining() - msgbPos;
+ msgA.limit(msgaLimit);
+ msg.position(msgbPos);
+ ByteBuffer msgB = msg.slice();
+ ArrayList<AMQDataBlock> frames = _decoder.decodeBuffer(msgA);
+ assertEquals(0, frames.size());
+ frames = _decoder.decodeBuffer(msgB);
+ assertEquals(1, frames.size());
+ if (frames.get(0) instanceof AMQFrame)
+ {
+ assertEquals(HeartbeatBody.FRAME.getBodyFrame().getFrameType(), ((AMQFrame) frames.get(0)).getBodyFrame().getFrameType());
+ }
+ else
+ {
+ fail("decode was not a frame");
+ }
+ }
+
+ public void testMultipleFrameDecode() throws AMQProtocolVersionException, AMQFrameDecodingException
+ {
+ ByteBuffer msgA = HeartbeatBody.FRAME.toNioByteBuffer();
+ ByteBuffer msgB = HeartbeatBody.FRAME.toNioByteBuffer();
+ ByteBuffer msg = ByteBuffer.allocate(msgA.remaining() + msgB.remaining());
+ msg.put(msgA);
+ msg.put(msgB);
+ msg.flip();
+ ArrayList<AMQDataBlock> frames = _decoder.decodeBuffer(msg);
+ assertEquals(2, frames.size());
+ for (AMQDataBlock frame : frames)
+ {
+ if (frame instanceof AMQFrame)
+ {
+ assertEquals(HeartbeatBody.FRAME.getBodyFrame().getFrameType(), ((AMQFrame) frame).getBodyFrame().getFrameType());
+ }
+ else
+ {
+ fail("decode was not a frame");
+ }
+ }
+ }
+
+ public void testMultiplePartialFrameDecode() throws AMQProtocolVersionException, AMQFrameDecodingException
+ {
+ 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);
+ int limit = msgB.limit();
+ int pos = msgB.remaining() / 2;
+ msgB.limit(pos);
+ sliceA.put(msgB);
+ sliceA.flip();
+ msgB.limit(limit);
+ msgB.position(pos);
+
+ ByteBuffer sliceB = ByteBuffer.allocate(msgB.remaining() + pos);
+ sliceB.put(msgB);
+ msgC.limit(pos);
+ sliceB.put(msgC);
+ sliceB.flip();
+ msgC.limit(limit);
+
+ ArrayList<AMQDataBlock> frames = _decoder.decodeBuffer(sliceA);
+ assertEquals(1, frames.size());
+ frames = _decoder.decodeBuffer(sliceB);
+ assertEquals(1, frames.size());
+ frames = _decoder.decodeBuffer(msgC);
+ assertEquals(1, frames.size());
+ for (AMQDataBlock frame : frames)
+ {
+ if (frame instanceof AMQFrame)
+ {
+ assertEquals(HeartbeatBody.FRAME.getBodyFrame().getFrameType(), ((AMQFrame) frame).getBodyFrame().getFrameType());
+ }
+ else
+ {
+ fail("decode was not a frame");
+ }
+ }
+ }
+
+}
diff --git a/java/common/src/test/java/org/apache/qpid/codec/MockAMQVersionAwareProtocolSession.java b/java/common/src/test/java/org/apache/qpid/codec/MockAMQVersionAwareProtocolSession.java
new file mode 100644
index 0000000000..c3b91d5d18
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/codec/MockAMQVersionAwareProtocolSession.java
@@ -0,0 +1,84 @@
+package org.apache.qpid.codec;
+
+import java.nio.ByteBuffer;
+
+import org.apache.qpid.AMQException;
+import org.apache.qpid.framing.AMQDataBlock;
+import org.apache.qpid.framing.AMQMethodBody;
+import org.apache.qpid.framing.ContentBody;
+import org.apache.qpid.framing.ContentHeaderBody;
+import org.apache.qpid.framing.HeartbeatBody;
+import org.apache.qpid.framing.MethodRegistry;
+import org.apache.qpid.framing.ProtocolVersion;
+import org.apache.qpid.protocol.AMQVersionAwareProtocolSession;
+import org.apache.qpid.transport.Sender;
+
+public class MockAMQVersionAwareProtocolSession implements AMQVersionAwareProtocolSession
+{
+
+ public void contentBodyReceived(int channelId, ContentBody body) throws AMQException
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void contentHeaderReceived(int channelId, ContentHeaderBody body) throws AMQException
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public MethodRegistry getMethodRegistry()
+ {
+ return MethodRegistry.getMethodRegistry(ProtocolVersion.v0_9);
+ }
+
+ public void heartbeatBodyReceived(int channelId, HeartbeatBody body) throws AMQException
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void init()
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void methodFrameReceived(int channelId, AMQMethodBody body) throws AMQException
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setSender(Sender<ByteBuffer> sender)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void writeFrame(AMQDataBlock frame)
+ {
+ // TODO Auto-generated method stub
+
+ }
+
+ public byte getProtocolMajorVersion()
+ {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public byte getProtocolMinorVersion()
+ {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public ProtocolVersion getProtocolVersion()
+ {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/java/common/src/test/java/org/apache/qpid/framing/abstraction/MessagePublishInfoImplTest.java b/java/common/src/test/java/org/apache/qpid/framing/abstraction/MessagePublishInfoImplTest.java
new file mode 100644
index 0000000000..3243136287
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/framing/abstraction/MessagePublishInfoImplTest.java
@@ -0,0 +1,99 @@
+/*
+ *
+ * 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.abstraction;
+
+import junit.framework.TestCase;
+import org.apache.qpid.framing.AMQShortString;
+import org.apache.qpid.framing.abstraction.MessagePublishInfoImpl;
+
+public class MessagePublishInfoImplTest extends TestCase
+{
+ MessagePublishInfoImpl _mpi;
+ final AMQShortString _exchange = new AMQShortString("exchange");
+ final AMQShortString _routingKey = new AMQShortString("routingKey");
+
+ public void setUp()
+ {
+ _mpi = new MessagePublishInfoImpl(_exchange, true, true, _routingKey);
+ }
+
+ /** Test that we can update the exchange value. */
+ public void testExchange()
+ {
+ assertEquals(_exchange, _mpi.getExchange());
+ AMQShortString newExchange = new AMQShortString("newExchange");
+ //Check we can update the exchange
+ _mpi.setExchange(newExchange);
+ assertEquals(newExchange, _mpi.getExchange());
+ //Ensure that the new exchange doesn't equal the old one
+ assertFalse(_exchange.equals(_mpi.getExchange()));
+ }
+
+ /**
+ * Check that the immedate value is set correctly and defaulted correctly
+ */
+ public void testIsImmediate()
+ {
+ //Check that the set value is correct
+ assertTrue("Set value for immediate not as expected", _mpi.isImmediate());
+
+ MessagePublishInfoImpl mpi = new MessagePublishInfoImpl();
+
+ assertFalse("Default value for immediate should be false", mpi.isImmediate());
+
+ mpi.setImmediate(true);
+
+ assertTrue("Updated value for immediate not as expected", mpi.isImmediate());
+
+ }
+
+ /**
+ * Check that the mandatory value is set correctly and defaulted correctly
+ */
+ public void testIsMandatory()
+ {
+ assertTrue("Set value for mandatory not as expected", _mpi.isMandatory());
+
+ MessagePublishInfoImpl mpi = new MessagePublishInfoImpl();
+
+ assertFalse("Default value for mandatory should be false", mpi.isMandatory());
+
+ mpi.setMandatory(true);
+
+ assertTrue("Updated value for mandatory not as expected", mpi.isMandatory());
+ }
+
+ /**
+ * Check that the routingKey value is perserved
+ */
+ public void testRoutingKey()
+ {
+ assertEquals(_routingKey, _mpi.getRoutingKey());
+ AMQShortString newRoutingKey = new AMQShortString("newRoutingKey");
+
+ //Check we can update the routingKey
+ _mpi.setRoutingKey(newRoutingKey);
+ assertEquals(newRoutingKey, _mpi.getRoutingKey());
+ //Ensure that the new routingKey doesn't equal the old one
+ assertFalse(_routingKey.equals(_mpi.getRoutingKey()));
+
+ }
+}
diff --git a/java/common/src/test/java/org/apache/qpid/pool/PoolingFilterTest.java b/java/common/src/test/java/org/apache/qpid/pool/PoolingFilterTest.java
deleted file mode 100644
index 6383d52298..0000000000
--- a/java/common/src/test/java/org/apache/qpid/pool/PoolingFilterTest.java
+++ /dev/null
@@ -1,111 +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.pool;
-
-import junit.framework.TestCase;
-import junit.framework.Assert;
-import org.apache.qpid.session.TestSession;
-import org.apache.mina.common.IoFilter;
-import org.apache.mina.common.IoSession;
-import org.apache.mina.common.IdleStatus;
-
-import java.util.concurrent.RejectedExecutionException;
-
-public class PoolingFilterTest extends TestCase
-{
- private PoolingFilter _pool;
- ReferenceCountingExecutorService _executorService;
-
- public void setUp()
- {
-
- //Create Pool
- _executorService = ReferenceCountingExecutorService.getInstance();
- _executorService.acquireExecutorService();
- _pool = PoolingFilter.createAynschWritePoolingFilter(_executorService,
- "AsynchronousWriteFilter");
-
- }
-
- public void testRejectedExecution() throws Exception
- {
-
- TestSession testSession = new TestSession();
- _pool.createNewJobForSession(testSession);
- _pool.filterWrite(new NoOpFilter(), testSession, new IoFilter.WriteRequest("Message"));
-
- //Shutdown the pool
- _executorService.getPool().shutdownNow();
-
- try
- {
-
- testSession = new TestSession();
- _pool.createNewJobForSession(testSession);
- //prior to fix for QPID-172 this would throw RejectedExecutionException
- _pool.filterWrite(null, testSession, null);
- }
- catch (RejectedExecutionException rje)
- {
- Assert.fail("RejectedExecutionException should not occur after pool has shutdown:" + rje);
- }
- }
-
- private static class NoOpFilter implements IoFilter.NextFilter
- {
-
- public void sessionOpened(IoSession session)
- {
- }
-
- public void sessionClosed(IoSession session)
- {
- }
-
- public void sessionIdle(IoSession session, IdleStatus status)
- {
- }
-
- public void exceptionCaught(IoSession session, Throwable cause)
- {
- }
-
- public void messageReceived(IoSession session, Object message)
- {
- }
-
- public void messageSent(IoSession session, Object message)
- {
- }
-
- public void filterWrite(IoSession session, IoFilter.WriteRequest writeRequest)
- {
- }
-
- public void filterClose(IoSession session)
- {
- }
-
- public void sessionCreated(IoSession session)
- {
- }
- }
-}
diff --git a/java/common/src/test/java/org/apache/qpid/thread/ThreadFactoryTest.java b/java/common/src/test/java/org/apache/qpid/thread/ThreadFactoryTest.java
new file mode 100644
index 0000000000..9932633cb9
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/thread/ThreadFactoryTest.java
@@ -0,0 +1,46 @@
+package org.apache.qpid.thread;
+
+import junit.framework.TestCase;
+
+public class ThreadFactoryTest extends TestCase
+{
+ public void testThreadFactory()
+ {
+ Class threadFactoryClass = null;
+ try
+ {
+ threadFactoryClass = Class.forName(System.getProperty("qpid.thread_factory",
+ "org.apache.qpid.thread.DefaultThreadFactory"));
+ }
+ // If the thread factory class was wrong it will flagged way before it gets here.
+ catch(Exception e)
+ {
+ fail("Invalid thread factory class");
+ }
+
+ assertEquals(threadFactoryClass, Threading.getThreadFactory().getClass());
+ }
+
+ public void testThreadCreate()
+ {
+ Runnable r = new Runnable(){
+
+ public void run(){
+
+ }
+ };
+
+ Thread t = null;
+ try
+ {
+ t = Threading.getThreadFactory().createThread(r,5);
+ }
+ catch(Exception e)
+ {
+ fail("Error creating thread using Qpid thread factory");
+ }
+
+ assertNotNull(t);
+ assertEquals(5,t.getPriority());
+ }
+}
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 b9ca210483..8aa8c5f647 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
@@ -26,62 +26,148 @@ import org.apache.qpid.util.concurrent.Condition;
import org.apache.qpid.transport.network.ConnectionBinding;
import org.apache.qpid.transport.network.io.IoAcceptor;
-import org.apache.qpid.transport.network.io.IoTransport;
import org.apache.qpid.transport.util.Logger;
+import org.apache.qpid.transport.util.Waiter;
import junit.framework.TestCase;
-import java.util.Random;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Collections;
+import java.io.IOException;
+
+import static org.apache.qpid.transport.Option.*;
/**
* ConnectionTest
*/
-public class ConnectionTest extends TestCase
+public class ConnectionTest extends TestCase 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>();
+ private List<MessageTransfer> incoming = new ArrayList<MessageTransfer>();
+
+ private IoAcceptor _ioa = null;
+
protected void setUp() throws Exception
{
super.setUp();
port = AvailablePortFinder.getNextAvailable(12000);
+ }
- ConnectionDelegate server = new ConnectionDelegate() {
- public void init(Channel ch, ProtocolHeader hdr) {
- ch.getConnection().close();
- }
+ protected void tearDown() throws Exception
+ {
+ if (_ioa != null)
+ {
+ _ioa.close();
+ }
- public SessionDelegate getSessionDelegate() {
- return new SessionDelegate() {};
- }
- public void exception(Throwable t) {
- log.error(t, "exception caught");
- }
- public void closed() {}
- };
+ super.tearDown();
+ }
+
+ public void opened(Session ssn) {}
+
+ public void resumed(Session ssn) {}
+
+ public void message(final Session ssn, MessageTransfer xfr)
+ {
+ if (queue)
+ {
+ messages.add(xfr);
+ ssn.processed(xfr);
+ return;
+ }
- IoAcceptor ioa = new IoAcceptor
- ("localhost", port, new ConnectionBinding(server));
- ioa.start();
+ String body = xfr.getBodyString();
+
+ if (body.startsWith("CLOSE"))
+ {
+ ssn.getConnection().close();
+ }
+ else if (body.startsWith("DELAYED_CLOSE"))
+ {
+ ssn.processed(xfr);
+ new Thread()
+ {
+ public void run()
+ {
+ try
+ {
+ sleep(3000);
+ }
+ catch (InterruptedException e)
+ {
+ throw new RuntimeException(e);
+ }
+ ssn.getConnection().close();
+ }
+ }.start();
+ }
+ else if (body.startsWith("ECHO"))
+ {
+ int id = xfr.getId();
+ ssn.invoke(xfr);
+ ssn.processed(id);
+ }
+ else if (body.startsWith("SINK"))
+ {
+ ssn.processed(xfr);
+ }
+ else if (body.startsWith("DROP"))
+ {
+ // do nothing
+ }
+ else if (body.startsWith("EXCP"))
+ {
+ ExecutionException exc = new ExecutionException();
+ exc.setDescription("intentional exception for testing");
+ ssn.invoke(exc);
+ ssn.close();
+ }
+ else
+ {
+ throw new IllegalArgumentException
+ ("unrecognized message: " + body);
+ }
+ }
+
+ public void exception(Session ssn, SessionException exc)
+ {
+ throw exc;
+ }
+
+ public void closed(Session ssn) {}
+
+ private void send(Session ssn, String msg)
+ {
+ send(ssn, msg, false);
+ }
+
+ private void send(Session ssn, String msg, boolean sync)
+ {
+ ssn.messageTransfer
+ ("xxx", MessageAcceptMode.NONE, MessageAcquireMode.PRE_ACQUIRED,
+ null, msg, sync ? SYNC : NONE);
}
private Connection connect(final Condition closed)
{
- Connection conn = IoTransport.connect("localhost", port, new ConnectionDelegate()
+ Connection conn = new Connection();
+ conn.setConnectionListener(new ConnectionListener()
{
- public SessionDelegate getSessionDelegate()
+ public void opened(Connection conn) {}
+ public void exception(Connection conn, ConnectionException exc)
{
- return new SessionDelegate() {};
+ exc.printStackTrace();
}
- public void exception(Throwable t)
- {
- t.printStackTrace();
- }
- public void closed()
+ public void closed(Connection conn)
{
if (closed != null)
{
@@ -89,27 +175,94 @@ public class ConnectionTest extends TestCase
}
}
});
-
- conn.send(new ProtocolHeader(1, 0, 10));
+ conn.connect("localhost", port, null, "guest", "guest", false);
return conn;
}
+ public void testProtocolNegotiationExceptionOverridesCloseException() throws Exception
+ {
+ // Force os.name to be windows to exercise code in IoReceiver
+ // that looks for the value of os.name
+ System.setProperty("os.name","windows");
+
+ // Start server as 0-9 to froce a ProtocolVersionException
+ startServer(new ProtocolHeader(1, 0, 9));
+
+ Condition closed = new Condition();
+
+ try
+ {
+ connect(closed);
+ fail("ProtocolVersionException expected");
+ }
+ catch (ProtocolVersionException pve)
+ {
+ //Expected code path
+ }
+ catch (Exception e)
+ {
+ fail("ProtocolVersionException expected. Got:" + e.getMessage());
+ }
+ }
+
+ private void startServer()
+ {
+ startServer(new ProtocolHeader(1, 0, 10));
+ }
+
+ private void startServer(final ProtocolHeader protocolHeader)
+ {
+ ConnectionDelegate server = new ServerDelegate()
+ {
+ @Override
+ public void init(Connection conn, ProtocolHeader hdr)
+ {
+ conn.send(protocolHeader);
+ List<Object> utf8 = new ArrayList<Object>();
+ utf8.add("utf8");
+ conn.connectionStart(null, Collections.EMPTY_LIST, utf8);
+ }
+
+ @Override
+ public Session getSession(Connection conn, SessionAttach atc)
+ {
+ Session ssn = super.getSession(conn, atc);
+ ssn.setSessionListener(ConnectionTest.this);
+ return ssn;
+ }
+ };
+
+ try
+ {
+ _ioa = new IoAcceptor("localhost", port, ConnectionBinding.get(server));
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace();
+ fail("Unable to start Server for test due to:" + e.getMessage());
+ }
+
+ _ioa.start();
+ }
+
public void testClosedNotificationAndWriteToClosed() throws Exception
{
+ startServer();
+
Condition closed = new Condition();
Connection conn = connect(closed);
+
+ Session ssn = conn.createSession(1);
+ send(ssn, "CLOSE");
+
if (!closed.get(3000))
{
fail("never got notified of connection close");
}
- Channel ch = conn.getChannel(0);
- Session ssn = new Session("test".getBytes());
- ssn.attach(ch);
-
try
{
- ssn.sessionAttach(ssn.getName());
+ conn.connectionCloseOk();
fail("writing to a closed socket succeeded");
}
catch (TransportException e)
@@ -118,4 +271,176 @@ public class ConnectionTest extends TestCase
}
}
+ 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
+ {
+ startServer();
+
+ Connection conn = new Connection();
+ conn.setConnectionListener(new FailoverConnectionListener());
+ conn.connect("localhost", port, null, "guest", "guest");
+ Session ssn = conn.createSession(1);
+ ssn.setSessionListener(new TestSessionListener());
+
+ send(ssn, "SINK 0");
+ send(ssn, "ECHO 1");
+ send(ssn, "ECHO 2");
+
+ ssn.sync();
+
+ String[] msgs = { "DROP 3", "DROP 4", "DROP 5", "CLOSE 6", "SINK 7" };
+ for (String m : msgs)
+ {
+ send(ssn, m);
+ }
+
+ ssn.sync();
+
+ assertEquals(msgs.length, messages.size());
+ for (int i = 0; i < msgs.length; i++)
+ {
+ assertEquals(msgs[i], messages.get(i).getBodyString());
+ }
+
+ queue = false;
+
+ send(ssn, "ECHO 8");
+ send(ssn, "ECHO 9");
+
+ synchronized (incoming)
+ {
+ Waiter w = new Waiter(incoming, 30000);
+ while (w.hasTime() && incoming.size() < 4)
+ {
+ w.await();
+ }
+
+ assertEquals(4, incoming.size());
+ assertEquals("ECHO 1", incoming.get(0).getBodyString());
+ assertEquals(0, incoming.get(0).getId());
+ assertEquals("ECHO 2", incoming.get(1).getBodyString());
+ assertEquals(1, incoming.get(1).getId());
+ assertEquals("ECHO 8", incoming.get(2).getBodyString());
+ assertEquals(0, incoming.get(0).getId());
+ assertEquals("ECHO 9", incoming.get(3).getBodyString());
+ assertEquals(1, incoming.get(1).getId());
+ }
+ }
+
+ public void testResumeEmptyReplayBuffer() throws InterruptedException
+ {
+ startServer();
+
+ Connection conn = new Connection();
+ conn.setConnectionListener(new FailoverConnectionListener());
+ conn.connect("localhost", port, null, "guest", "guest");
+ Session ssn = conn.createSession(1);
+ ssn.setSessionListener(new TestSessionListener());
+
+ send(ssn, "SINK 0");
+ send(ssn, "SINK 1");
+ send(ssn, "DELAYED_CLOSE 2");
+ ssn.sync();
+ Thread.sleep(6000);
+ send(ssn, "SINK 3");
+ ssn.sync();
+ System.out.println(messages);
+ assertEquals(1, messages.size());
+ assertEquals("SINK 3", messages.get(0).getBodyString());
+ }
+
+ public void testFlushExpected() throws InterruptedException
+ {
+ startServer();
+
+ Connection conn = new Connection();
+ conn.connect("localhost", port, null, "guest", "guest");
+ Session ssn = conn.createSession();
+ ssn.sessionFlush(EXPECTED);
+ send(ssn, "SINK 0");
+ ssn.sessionFlush(EXPECTED);
+ send(ssn, "SINK 1");
+ ssn.sync();
+ }
+
+ public void testHeartbeat()
+ {
+ startServer();
+ Connection conn = new Connection();
+ conn.connect("localhost", port, null, "guest", "guest");
+ conn.connectionHeartbeat();
+ conn.close();
+ }
+
+ public void testExecutionExceptionInvoke() throws Exception
+ {
+ startServer();
+
+ Connection conn = new Connection();
+ conn.connect("localhost", port, null, "guest", "guest");
+ Session ssn = conn.createSession();
+ send(ssn, "EXCP 0");
+ Thread.sleep(3000);
+ try
+ {
+ send(ssn, "SINK 1");
+ }
+ catch (SessionException exc)
+ {
+ assertNotNull(exc.getException());
+ }
+ }
+
+ public void testExecutionExceptionSync() throws Exception
+ {
+ startServer();
+
+ Connection conn = new Connection();
+ conn.connect("localhost", port, null, "guest", "guest");
+ Session ssn = conn.createSession();
+ send(ssn, "EXCP 0", true);
+ try
+ {
+ ssn.sync();
+ }
+ catch (SessionException exc)
+ {
+ assertNotNull(exc.getException());
+ }
+ }
+
}
diff --git a/java/common/src/test/java/org/apache/qpid/transport/GenTest.java b/java/common/src/test/java/org/apache/qpid/transport/GenTest.java
new file mode 100644
index 0000000000..512a0a29a6
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/transport/GenTest.java
@@ -0,0 +1,44 @@
+/*
+ *
+ * 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 junit.framework.TestCase;
+
+/**
+ * GenTest
+ *
+ */
+
+public class GenTest extends TestCase
+{
+
+ public void testBooleans()
+ {
+ QueueDeclare qd = new QueueDeclare().queue("test-queue").durable(false);
+ assertEquals(qd.getQueue(), "test-queue");
+ assertFalse("durable should be false", qd.getDurable());
+ qd.setDurable(true);
+ assertTrue("durable should be true", qd.getDurable());
+ qd.setDurable(false);
+ assertFalse("durable should be false again", qd.getDurable());
+ }
+
+}
diff --git a/java/common/src/test/java/org/apache/qpid/transport/TestNetworkDriver.java b/java/common/src/test/java/org/apache/qpid/transport/TestNetworkDriver.java
new file mode 100644
index 0000000000..a4c4b59cdd
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/transport/TestNetworkDriver.java
@@ -0,0 +1,122 @@
+/*
+ *
+ * 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.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;
+
+/**
+ * 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 TestNetworkDriver implements NetworkDriver
+{
+ private final ConcurrentMap attributes = new ConcurrentHashMap();
+ private String _remoteAddress = "127.0.0.1";
+ private String _localAddress = "127.0.0.1";
+ private int _port = 1;
+
+ public TestNetworkDriver()
+ {
+ }
+
+ public void setRemoteAddress(String string)
+ {
+ this._remoteAddress = string;
+ }
+
+ public void setPort(int _port)
+ {
+ this._port = _port;
+ }
+
+ public int getPort()
+ {
+ return _port;
+ }
+
+ public void bind(int port, InetAddress[] addresses, ProtocolEngineFactory protocolFactory,
+ NetworkDriverConfiguration config, SSLContextFactory sslFactory) throws BindException
+ {
+
+ }
+
+ public SocketAddress getLocalAddress()
+ {
+ return new InetSocketAddress(_localAddress, _port);
+ }
+
+ public SocketAddress getRemoteAddress()
+ {
+ return new InetSocketAddress(_remoteAddress, _port);
+ }
+
+ 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(long l)
+ {
+
+ }
+
+ public void setLocalAddress(String localAddress)
+ {
+ _localAddress = localAddress;
+ }
+
+}
diff --git a/java/common/src/test/java/org/apache/qpid/transport/codec/BBEncoderTest.java b/java/common/src/test/java/org/apache/qpid/transport/codec/BBEncoderTest.java
new file mode 100644
index 0000000000..79bf184fe2
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/transport/codec/BBEncoderTest.java
@@ -0,0 +1,47 @@
+/*
+ *
+ * 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.codec;
+
+import junit.framework.TestCase;
+
+import java.nio.ByteBuffer;
+
+/**
+ * BBEncoderTest
+ *
+ */
+
+public class BBEncoderTest extends TestCase
+{
+
+ public void testGrow()
+ {
+ BBEncoder enc = new BBEncoder(4);
+ enc.writeInt32(0xDEADBEEF);
+ ByteBuffer buf = enc.buffer();
+ assertEquals(0xDEADBEEF, buf.getInt(0));
+ enc.writeInt32(0xBEEFDEAD);
+ buf = enc.buffer();
+ assertEquals(0xDEADBEEF, buf.getInt(0));
+ assertEquals(0xBEEFDEAD, buf.getInt(4));
+ }
+
+}
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..5af07d9735
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/transport/network/mina/MINANetworkDriverTest.java
@@ -0,0 +1,491 @@
+/*
+ *
+ * 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 final 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();
+ }
+
+ @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
new file mode 100644
index 0000000000..7eba5f092e
--- /dev/null
+++ b/java/common/src/test/java/org/apache/qpid/util/FileUtilsTest.java
@@ -0,0 +1,612 @@
+/*
+ *
+ * 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.util;
+
+import junit.framework.TestCase;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.List;
+
+public class FileUtilsTest extends TestCase
+{
+ private static final String COPY = "-Copy";
+ private static final String SUB = "-Sub";
+
+ /**
+ * Additional test for the copy method.
+ * Ensures that the directory count did increase by more than 1 after the copy.
+ */
+ public void testCopyFile()
+ {
+ final String TEST_DATA = "FileUtilsTest-testCopy-TestDataTestDataTestDataTestDataTestDataTestData";
+ String fileName = "FileUtilsTest-testCopy";
+ String fileNameCopy = fileName + COPY;
+
+ File[] beforeCopyFileList = null;
+
+ //Create initial file
+ File test = createTestFile(fileName, TEST_DATA);
+
+ try
+ {
+ //Check number of files before copy
+ beforeCopyFileList = test.getAbsoluteFile().getParentFile().listFiles();
+ int beforeCopy = beforeCopyFileList.length;
+
+ //Perform Copy
+ File destination = new File(fileNameCopy);
+ FileUtils.copy(test, destination);
+ //Ensure the JVM cleans up if cleanup failues
+ destination.deleteOnExit();
+
+ //Retrieve counts after copy
+ int afterCopy = test.getAbsoluteFile().getParentFile().listFiles().length;
+
+ int afterCopyFromCopy = new File(fileNameCopy).getAbsoluteFile().getParentFile().listFiles().length;
+
+ // Validate the copy counts
+ assertEquals("The file listing from the original and the copy differ in length.", afterCopy, afterCopyFromCopy);
+ assertEquals("The number of files did not increase.", beforeCopy + 1, afterCopy);
+ assertEquals("The number of files did not increase.", beforeCopy + 1, afterCopyFromCopy);
+
+ //Validate copy
+ // Load content
+ String copiedFileContent = FileUtils.readFileAsString(fileNameCopy);
+ assertEquals(TEST_DATA, copiedFileContent);
+ }
+ finally // Ensure clean
+ {
+ //Clean up
+ assertTrue("Unable to cleanup", FileUtils.deleteFile(fileNameCopy));
+
+ //Check file list after cleanup
+ File[] afterCleanup = new File(test.getAbsoluteFile().getParent()).listFiles();
+ checkFileLists(beforeCopyFileList, afterCleanup);
+
+ //Remove original file
+ assertTrue("Unable to cleanup", test.delete());
+ }
+ }
+
+ /**
+ * Create and Copy the following structure:
+ *
+ * testDirectory --+
+ * +-- testSubDirectory --+
+ * +-- testSubFile
+ * +-- File
+ *
+ * to testDirectory-Copy
+ *
+ * Validate that the file count in the copy is correct and contents of the copied files is correct.
+ */
+ public void testCopyRecursive()
+ {
+ final String TEST_DATA = "FileUtilsTest-testDirectoryCopy-TestDataTestDataTestDataTestDataTestDataTestData";
+ String fileName = "FileUtilsTest-testCopy";
+ String TEST_DIR = "testDirectoryCopy";
+
+ //Create Initial Structure
+ File testDir = new File(TEST_DIR);
+
+ //Check number of files before copy
+ File[] beforeCopyFileList = testDir.getAbsoluteFile().getParentFile().listFiles();
+
+ try
+ {
+ //Create Directories
+ assertTrue("Test directory already exists cannot test.", !testDir.exists());
+
+ if (!testDir.mkdir())
+ {
+ fail("Unable to make test Directory");
+ }
+
+ File testSubDir = new File(TEST_DIR + File.separator + TEST_DIR + SUB);
+ if (!testSubDir.mkdir())
+ {
+ fail("Unable to make test sub Directory");
+ }
+
+ //Create Files
+ createTestFile(testDir.toString() + File.separator + fileName, TEST_DATA);
+ createTestFile(testSubDir.toString() + File.separator + fileName + SUB, TEST_DATA);
+
+ //Ensure the JVM cleans up if cleanup failues
+ testSubDir.deleteOnExit();
+ testDir.deleteOnExit();
+
+ //Perform Copy
+ File copyDir = new File(testDir.toString() + COPY);
+ try
+ {
+ FileUtils.copyRecursive(testDir, copyDir);
+ }
+ catch (FileNotFoundException e)
+ {
+ fail(e.getMessage());
+ }
+ catch (FileUtils.UnableToCopyException e)
+ {
+ fail(e.getMessage());
+ }
+
+ //Validate Copy
+ assertEquals("Copied directory should only have one file and one directory in it.", 2, copyDir.listFiles().length);
+
+ //Validate Copy File Contents
+ String copiedFileContent = FileUtils.readFileAsString(copyDir.toString() + File.separator + fileName);
+ assertEquals(TEST_DATA, copiedFileContent);
+
+ //Validate Name of Sub Directory
+ assertTrue("Expected subdirectory is not a directory", new File(copyDir.toString() + File.separator + TEST_DIR + SUB).isDirectory());
+
+ //Assert that it contains only one item
+ assertEquals("Copied sub directory should only have one directory in it.", 1, new File(copyDir.toString() + File.separator + TEST_DIR + SUB).listFiles().length);
+
+ //Validate content of Sub file
+ copiedFileContent = FileUtils.readFileAsString(copyDir.toString() + File.separator + TEST_DIR + SUB + File.separator + fileName + SUB);
+ assertEquals(TEST_DATA, copiedFileContent);
+ }
+ finally
+ {
+ //Clean up source and copy directory.
+ assertTrue("Unable to cleanup", FileUtils.delete(testDir, true));
+ assertTrue("Unable to cleanup", FileUtils.delete(new File(TEST_DIR + COPY), true));
+
+ //Check file list after cleanup
+ File[] afterCleanup = testDir.getAbsoluteFile().getParentFile().listFiles();
+ checkFileLists(beforeCopyFileList, afterCleanup);
+ }
+ }
+
+ /**
+ * Helper method to create a test file with a string content
+ *
+ * @param fileName The fileName to use in the creation
+ * @param test_data The data to store in the file
+ *
+ * @return The File reference
+ */
+ private File createTestFile(String fileName, String test_data)
+ {
+ File test = new File(fileName);
+
+ try
+ {
+ test.createNewFile();
+ //Ensure the JVM cleans up if cleanup failues
+ test.deleteOnExit();
+ }
+ catch (IOException e)
+ {
+ fail(e.getMessage());
+ }
+
+ BufferedWriter writer = null;
+ try
+ {
+ writer = new BufferedWriter(new FileWriter(test));
+ try
+ {
+ writer.write(test_data);
+ }
+ catch (IOException e)
+ {
+ fail(e.getMessage());
+ }
+ }
+ catch (IOException e)
+ {
+ fail(e.getMessage());
+ }
+ finally
+ {
+ try
+ {
+ if (writer != null)
+ {
+ writer.close();
+ }
+ }
+ catch (IOException e)
+ {
+ fail(e.getMessage());
+ }
+ }
+
+ return test;
+ }
+
+ /** Test that deleteFile only deletes the specified file */
+ public void testDeleteFile()
+ {
+ File test = new File("FileUtilsTest-testDelete");
+ //Record file count in parent directory to check it is not changed by delete
+ String path = test.getAbsolutePath();
+ File[] filesBefore = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles();
+ int fileCountBefore = filesBefore.length;
+
+ try
+ {
+ test.createNewFile();
+ //Ensure the JVM cleans up if cleanup failues
+ test.deleteOnExit();
+ }
+ catch (IOException e)
+ {
+ fail(e.getMessage());
+ }
+
+ assertTrue("File does not exists", test.exists());
+ assertTrue("File is not a file", test.isFile());
+
+ //Check that file creation can be seen on disk
+ int fileCountCreated = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles().length;
+ assertEquals("File creation was no registered", fileCountBefore + 1, fileCountCreated);
+
+ //Perform Delete
+ assertTrue("Unable to cleanup", FileUtils.deleteFile("FileUtilsTest-testDelete"));
+
+ assertTrue("File exists after delete", !test.exists());
+
+ //Check that after deletion the file count is now accurate
+ File[] filesAfter = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles();
+ int fileCountAfter = filesAfter.length;
+ assertEquals("File creation was no registered", fileCountBefore, fileCountAfter);
+
+ checkFileLists(filesBefore, filesAfter);
+ }
+
+ public void testDeleteNonExistentFile()
+ {
+ File test = new File("FileUtilsTest-testDelete-" + System.currentTimeMillis());
+
+ assertTrue("File exists", !test.exists());
+ assertFalse("File is a directory", test.isDirectory());
+
+ assertTrue("Delete Succeeded ", !FileUtils.delete(test, true));
+ }
+
+ public void testDeleteNull()
+ {
+ try
+ {
+ FileUtils.delete(null, true);
+ fail("Delete with null value should throw NPE.");
+ }
+ catch (NullPointerException npe)
+ {
+ // expected path
+ }
+ }
+
+ /**
+ * Given two lists of File arrays ensure they are the same length and all entries in Before are in After
+ *
+ * @param filesBefore File[]
+ * @param filesAfter File[]
+ */
+ private void checkFileLists(File[] filesBefore, File[] filesAfter)
+ {
+ assertNotNull("Before file list cannot be null", filesBefore);
+ assertNotNull("After file list cannot be null", filesAfter);
+
+ assertEquals("File lists are unequal", filesBefore.length, filesAfter.length);
+
+ for (File fileBefore : filesBefore)
+ {
+ boolean found = false;
+
+ for (File fileAfter : filesAfter)
+ {
+ if (fileBefore.getAbsolutePath().equals(fileAfter.getAbsolutePath()))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ assertTrue("File'" + fileBefore.getName() + "' was not in directory afterwards", found);
+ }
+ }
+
+ public void testNonRecursiveNonEmptyDirectoryDeleteFails()
+ {
+ String directoryName = "FileUtilsTest-testRecursiveDelete";
+ File test = new File(directoryName);
+
+ //Record file count in parent directory to check it is not changed by delete
+ String path = test.getAbsolutePath();
+ File[] filesBefore = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles();
+ int fileCountBefore = filesBefore.length;
+
+ assertTrue("Directory exists", !test.exists());
+
+ test.mkdir();
+
+ //Create a file in the directory
+ String fileName = test.getAbsolutePath() + File.separatorChar + "testFile";
+ File subFile = new File(fileName);
+ try
+ {
+ subFile.createNewFile();
+ //Ensure the JVM cleans up if cleanup failues
+ subFile.deleteOnExit();
+ }
+ catch (IOException e)
+ {
+ fail(e.getMessage());
+ }
+ //Ensure the JVM cleans up if cleanup failues
+ // This must be after the subFile as the directory must be empty before
+ // the delete is performed
+ test.deleteOnExit();
+
+ //Try and delete the non-empty directory
+ assertFalse("Non Empty Directory was successfully deleted.", FileUtils.deleteDirectory(directoryName));
+
+ //Check directory is still there
+ assertTrue("Directory was deleted.", test.exists());
+
+ // Clean up
+ assertTrue("Unable to cleanup", FileUtils.delete(test, true));
+
+ //Check that after deletion the file count is now accurate
+ File[] filesAfter = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles();
+ int fileCountAfter = filesAfter.length;
+ assertEquals("File creation was no registered", fileCountBefore, fileCountAfter);
+
+ checkFileLists(filesBefore, filesAfter);
+ }
+
+ /** Test that an empty directory can be deleted with deleteDirectory */
+ public void testEmptyDirectoryDelete()
+ {
+ String directoryName = "FileUtilsTest-testRecursiveDelete";
+ File test = new File(directoryName);
+
+ //Record file count in parent directory to check it is not changed by delete
+ String path = test.getAbsolutePath();
+ File[] filesBefore = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles();
+ int fileCountBefore = filesBefore.length;
+
+ assertTrue("Directory exists", !test.exists());
+
+ test.mkdir();
+ //Ensure the JVM cleans up if cleanup failues
+ test.deleteOnExit();
+
+ //Try and delete the empty directory
+ assertTrue("Non Empty Directory was successfully deleted.", FileUtils.deleteDirectory(directoryName));
+
+ //Check directory is still there
+ assertTrue("Directory was deleted.", !test.exists());
+
+ //Check that after deletion the file count is now accurate
+ File[] filesAfter = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles();
+ int fileCountAfter = filesAfter.length;
+ assertEquals("File creation was no registered", fileCountBefore, fileCountAfter);
+
+ checkFileLists(filesBefore, filesAfter);
+
+ }
+
+ /** Test that deleteDirectory on a non empty directory to complete */
+ public void testNonEmptyDirectoryDelete()
+ {
+ String directoryName = "FileUtilsTest-testRecursiveDelete";
+ File test = new File(directoryName);
+
+ assertTrue("Directory exists", !test.exists());
+
+ //Record file count in parent directory to check it is not changed by delete
+ String path = test.getAbsolutePath();
+ File[] filesBefore = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles();
+ int fileCountBefore = filesBefore.length;
+
+ test.mkdir();
+
+ //Create a file in the directory
+ String fileName = test.getAbsolutePath() + File.separatorChar + "testFile";
+ File subFile = new File(fileName);
+ try
+ {
+ subFile.createNewFile();
+ //Ensure the JVM cleans up if cleanup failues
+ subFile.deleteOnExit();
+ }
+ catch (IOException e)
+ {
+ fail(e.getMessage());
+ }
+
+ // Ensure the JVM cleans up if cleanup failues
+ // This must be after the subFile as the directory must be empty before
+ // the delete is performed
+ test.deleteOnExit();
+
+ //Try and delete the non-empty directory non-recursively
+ assertFalse("Non Empty Directory was successfully deleted.", FileUtils.delete(test, false));
+
+ //Check directory is still there
+ assertTrue("Directory was deleted.", test.exists());
+
+ // Clean up
+ assertTrue("Unable to cleanup", FileUtils.delete(test, true));
+
+ //Check that after deletion the file count is now accurate
+ File[] filesAfter = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles();
+ int fileCountAfter = filesAfter.length;
+ assertEquals("File creation was no registered", fileCountBefore, fileCountAfter);
+
+ checkFileLists(filesBefore, filesAfter);
+
+ }
+
+ /** Test that a recursive delete successeds */
+ public void testRecursiveDelete()
+ {
+ String directoryName = "FileUtilsTest-testRecursiveDelete";
+ File test = new File(directoryName);
+
+ assertTrue("Directory exists", !test.exists());
+
+ //Record file count in parent directory to check it is not changed by delete
+ String path = test.getAbsolutePath();
+ File[] filesBefore = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles();
+ int fileCountBefore = filesBefore.length;
+
+ test.mkdir();
+
+ createSubDir(directoryName, 2, 4);
+
+ //Ensure the JVM cleans up if cleanup failues
+ // This must be after the sub dir creation as the delete order is
+ // recorded and the directory must be empty to be deleted.
+ test.deleteOnExit();
+
+ assertFalse("Non recursive delete was able to directory", FileUtils.delete(test, false));
+
+ assertTrue("File does not exist after non recursive delete", test.exists());
+
+ assertTrue("Unable to cleanup", FileUtils.delete(test, true));
+
+ assertTrue("File exist after recursive delete", !test.exists());
+
+ //Check that after deletion the file count is now accurate
+ File[] filesAfter = new File(path.substring(0, path.lastIndexOf(File.separator))).listFiles();
+ int fileCountAfter = filesAfter.length;
+ assertEquals("File creation was no registered", fileCountBefore, fileCountAfter);
+
+ checkFileLists(filesBefore, filesAfter);
+
+ }
+
+ private void createSubDir(String path, int directories, int files)
+ {
+ File directory = new File(path);
+
+ assertTrue("Directory" + path + " does not exists", directory.exists());
+
+ for (int dir = 0; dir < directories; dir++)
+ {
+ String subDirName = path + File.separatorChar + "sub" + dir;
+ File subDir = new File(subDirName);
+
+ subDir.mkdir();
+
+ createSubDir(subDirName, directories - 1, files);
+ //Ensure the JVM cleans up if cleanup failues
+ // This must be after the sub dir creation as the delete order is
+ // recorded and the directory must be empty to be deleted.
+ subDir.deleteOnExit();
+ }
+
+ for (int file = 0; file < files; file++)
+ {
+ String subDirName = path + File.separatorChar + "file" + file;
+ File subFile = new File(subDirName);
+ try
+ {
+ subFile.createNewFile();
+ //Ensure the JVM cleans up if cleanup failues
+ subFile.deleteOnExit();
+ }
+ catch (IOException e)
+ {
+ fail(e.getMessage());
+ }
+ }
+ }
+
+ public static final String SEARCH_STRING = "testSearch";
+
+ /**
+ * Test searchFile(File file, String search) will find a match when it
+ * exists.
+ *
+ * @throws java.io.IOException if unable to perform test setup
+ */
+ public void testSearchSucceed() throws IOException
+ {
+ File _logfile = File.createTempFile("FileUtilsTest-testSearchSucceed", ".out");
+
+ prepareFileForSearchTest(_logfile);
+
+ List<String> results = FileUtils.searchFile(_logfile, SEARCH_STRING);
+
+ assertNotNull("Null result set returned", results);
+
+ assertEquals("Results do not contain expected count", 1, results.size());
+ }
+
+ /**
+ * Test searchFile(File file, String search) will not find a match when the
+ * test string does not exist.
+ *
+ * @throws java.io.IOException if unable to perform test setup
+ */
+ public void testSearchFail() throws IOException
+ {
+ File _logfile = File.createTempFile("FileUtilsTest-testSearchFail", ".out");
+
+ prepareFileForSearchTest(_logfile);
+
+ List<String> results = FileUtils.searchFile(_logfile, "Hello");
+
+ assertNotNull("Null result set returned", results);
+
+ //Validate we only got one message
+ if (results.size() > 0)
+ {
+ System.err.println("Unexpected messages");
+
+ for (String msg : results)
+ {
+ System.err.println(msg);
+ }
+ }
+
+ assertEquals("Results contains data when it was not expected",
+ 0, results.size());
+ }
+
+ /**
+ * Write the SEARCH_STRING in to the given file.
+ *
+ * @param logfile The file to write the SEARCH_STRING into
+ *
+ * @throws IOException if an error occurs
+ */
+ private void prepareFileForSearchTest(File logfile) throws IOException
+ {
+ BufferedWriter writer = new BufferedWriter(new FileWriter(logfile));
+ writer.append(SEARCH_STRING);
+ writer.flush();
+ writer.close();
+ }
+
+}
diff --git a/java/common/src/test/java/org/apache/qpid/util/SerialTest.java b/java/common/src/test/java/org/apache/qpid/util/SerialTest.java
index d3ab817b5d..b2578563e0 100644
--- a/java/common/src/test/java/org/apache/qpid/util/SerialTest.java
+++ b/java/common/src/test/java/org/apache/qpid/util/SerialTest.java
@@ -1,4 +1,25 @@
package org.apache.qpid.util;
+/*
+ *
+ * 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 junit.framework.TestCase;
diff --git a/java/common/templates/model/ProtocolVersionListClass.vm b/java/common/templates/model/ProtocolVersionListClass.vm
index 9ac6adfdf5..78605c70ff 100644
--- a/java/common/templates/model/ProtocolVersionListClass.vm
+++ b/java/common/templates/model/ProtocolVersionListClass.vm
@@ -41,12 +41,14 @@ public class ProtocolVersion implements Comparable
{
private final byte _majorVersion;
private final byte _minorVersion;
+ private final String _stringFormat;
public ProtocolVersion(byte majorVersion, byte minorVersion)
{
_majorVersion = majorVersion;
_minorVersion = minorVersion;
+ _stringFormat = _majorVersion+"-"+_minorVersion;
}
public byte getMajorVersion()
@@ -59,6 +61,22 @@ public class ProtocolVersion implements Comparable
return _minorVersion;
}
+ public byte getActualMinorVersion()
+ {
+ return _minorVersion > 90 ? (byte) (_minorVersion / 10) : _minorVersion;
+ }
+
+
+ public byte getRevisionVersion()
+ {
+ return _minorVersion > 90 ? (byte) (_minorVersion % 10) : (byte) 0;
+ }
+
+ public String toString()
+ {
+ return _stringFormat;
+ }
+
public int compareTo(Object o)
{
@@ -131,15 +149,20 @@ public class ProtocolVersion implements Comparable
private static final ProtocolVersion _defaultVersion;
+ public static final ProtocolVersion v0_10 = new ProtocolVersion((byte)0,(byte)10);
+
#foreach( $version in $model.getVersionSet() )
#set( $versionId = "v$version.getMajor()_$version.getMinor()" )
- public static final ProtocolVersion $versionId = new ProtocolVersion((byte)$version.getMajor(),(byte)$version.getMinor());
+ public static final ProtocolVersion $versionId = new ProtocolVersion((byte)$version.getMajor(),(byte)$version.getMinor());
#end
+
static
{
SortedSet<ProtocolVersion> versions = new TreeSet<ProtocolVersion>();
+ versions.add(v0_10);
+ _nameToVersionMap.put("0-10", v0_10);
#foreach( $version in $model.getVersionSet() )
#set( $versionId = "v$version.getMajor()_$version.getMinor()" )
versions.add($versionId);
diff --git a/java/common/templating.py b/java/common/templating.py
index 832b7ecb9c..732e96fa60 100644
--- a/java/common/templating.py
+++ b/java/common/templating.py
@@ -1,3 +1,21 @@
+#
+# 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.
+#
class Parser: