summaryrefslogtreecommitdiff
path: root/qpid/dotnet/Qpid.Codec/Demux/DemuxingProtocolCodecFactory.cs
diff options
context:
space:
mode:
Diffstat (limited to 'qpid/dotnet/Qpid.Codec/Demux/DemuxingProtocolCodecFactory.cs')
-rw-r--r--qpid/dotnet/Qpid.Codec/Demux/DemuxingProtocolCodecFactory.cs387
1 files changed, 387 insertions, 0 deletions
diff --git a/qpid/dotnet/Qpid.Codec/Demux/DemuxingProtocolCodecFactory.cs b/qpid/dotnet/Qpid.Codec/Demux/DemuxingProtocolCodecFactory.cs
new file mode 100644
index 0000000000..78276202d6
--- /dev/null
+++ b/qpid/dotnet/Qpid.Codec/Demux/DemuxingProtocolCodecFactory.cs
@@ -0,0 +1,387 @@
+/*
+ *
+ * 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.
+ *
+ */
+using System;
+using System.Collections;
+using Apache.Qpid.Buffer;
+
+namespace Apache.Qpid.Codec.Demux
+{
+ public class DemuxingProtocolCodecFactory : IProtocolCodecFactory
+ {
+ private ArrayList _decoderFactories = new ArrayList();
+ private ArrayList _encoderFactories = new ArrayList();
+
+ public void Register(Type encoderOrDecoderClass)
+ {
+ if (encoderOrDecoderClass == null)
+ {
+ throw new ArgumentNullException("encoderOrDecoderClass");
+ }
+
+ bool registered = false;
+ if (typeof(IMessageEncoder).IsAssignableFrom(encoderOrDecoderClass))
+ {
+ Register(new DefaultConstructorMessageEncoderFactory(encoderOrDecoderClass));
+ registered = true;
+ }
+
+ if (typeof(IMessageDecoder).IsAssignableFrom(encoderOrDecoderClass))
+ {
+ Register(new DefaultConstructorMessageDecoderFactory(encoderOrDecoderClass));
+ registered = true;
+ }
+
+ if (!registered)
+ {
+ throw new ArgumentException("Unregisterable type: " + encoderOrDecoderClass);
+ }
+ }
+
+ public void Register(IMessageEncoder encoder)
+ {
+ Register(new SingletonMessageEncoderFactory(encoder));
+ }
+
+ public void Register(IMessageEncoderFactory factory)
+ {
+ if (factory == null)
+ {
+ throw new ArgumentNullException("factory");
+ }
+
+ _encoderFactories.Add(factory);
+ }
+
+ public void Register(IMessageDecoder decoder)
+ {
+ Register(new SingletonMessageDecoderFactory(decoder));
+ }
+
+ public void Register(IMessageDecoderFactory factory)
+ {
+ if (factory == null)
+ {
+ throw new ArgumentNullException("factory");
+ }
+ _decoderFactories.Add(factory);
+ }
+
+ public IProtocolEncoder Encoder
+ {
+ get
+ {
+ return new ProtocolEncoderImpl(this);
+ }
+ }
+
+ public IProtocolDecoder Decoder
+ {
+ get
+ {
+ return new ProtocolDecoderImpl(this);
+ }
+ }
+
+ protected void DisposeCodecResources()
+ {
+ // Do nothing by default
+ }
+
+ private class ProtocolEncoderImpl : IProtocolEncoder
+ {
+ private readonly Hashtable _encoders = new Hashtable();
+
+ private DemuxingProtocolCodecFactory _enclosing;
+
+ public ProtocolEncoderImpl(DemuxingProtocolCodecFactory enclosing)
+ {
+ _enclosing = enclosing;
+ ArrayList encoderFactories = enclosing._encoderFactories;
+ for (int i = encoderFactories.Count - 1; i >= 0; i--)
+ {
+ IMessageEncoder encoder = ((IMessageEncoderFactory)encoderFactories[i]).NewEncoder();
+ foreach (Type type in encoder.MessageTypes.Keys)
+ {
+ _encoders[type] = encoder;
+ }
+ }
+ }
+
+ public void Encode(object message, IProtocolEncoderOutput output)
+ {
+ Type type = message.GetType();
+ IMessageEncoder encoder = FindEncoder(type);
+ if (encoder == null)
+ {
+ throw new ProtocolEncoderException("Unexpected message type: " + type);
+ }
+
+ encoder.Encode(message, output);
+ }
+
+ private IMessageEncoder FindEncoder(Type type)
+ {
+ IMessageEncoder encoder = (IMessageEncoder)_encoders[type];
+ if (encoder == null)
+ {
+ encoder = FindEncoder(type, new Hashtable());
+ }
+
+ return encoder;
+ }
+
+ private IMessageEncoder FindEncoder(Type type, Hashtable triedClasses)
+ {
+ IMessageEncoder encoder;
+
+ if (triedClasses.Contains(type))
+ {
+ return null;
+ }
+ triedClasses[type] = 1;
+
+ encoder = (IMessageEncoder)_encoders[type];
+ if (encoder == null)
+ {
+ encoder = FindEncoder(type, triedClasses);
+ if (encoder != null)
+ {
+ return encoder;
+ }
+
+ Type[] interfaces = type.GetInterfaces();
+ for (int i = 0; i < interfaces.Length; i++)
+ {
+ encoder = FindEncoder(interfaces[i], triedClasses);
+ if (encoder != null)
+ {
+ return encoder;
+ }
+ }
+
+ return null;
+ }
+ else
+ return encoder;
+ }
+
+ public void Dispose()
+ {
+ _enclosing.DisposeCodecResources();
+ }
+ }
+
+ private class ProtocolDecoderImpl : CumulativeProtocolDecoder
+ {
+ private readonly IMessageDecoder[] _decoders;
+ private IMessageDecoder _currentDecoder;
+ private DemuxingProtocolCodecFactory _enclosing;
+
+ public ProtocolDecoderImpl(DemuxingProtocolCodecFactory enclosing)
+ {
+ _enclosing = enclosing;
+ ArrayList decoderFactories = _enclosing._decoderFactories;
+ _decoders = new IMessageDecoder[decoderFactories.Count];
+ for (int i = decoderFactories.Count - 1; i >= 0; i--)
+ {
+ _decoders[i] = ((IMessageDecoderFactory) decoderFactories[i]).NewDecoder();
+ }
+ }
+
+ protected override bool DoDecode(ByteBuffer input, IProtocolDecoderOutput output)
+ {
+ MessageDecoderResult result;
+ if (_currentDecoder == null)
+ {
+ IMessageDecoder[] decoders = _decoders;
+ int undecodables = 0;
+
+ for (int i = decoders.Length - 1; i >= 0; i --)
+ {
+ IMessageDecoder decoder = decoders[i];
+ int limit = input.Limit;
+ int pos = input.Position;
+
+ try
+ {
+ result = decoder.Decodable(input);
+ }
+ finally
+ {
+ input.Position = pos;
+ input.Limit = limit;
+ }
+
+ if (result == MessageDecoderResult.OK)
+ {
+ _currentDecoder = decoder;
+ break;
+ }
+ else if(result == MessageDecoderResult.NOT_OK)
+ {
+ undecodables ++;
+ }
+ else if (result != MessageDecoderResult.NEED_DATA)
+ {
+ throw new Exception("Unexpected decode result (see your decodable()): " + result);
+ }
+ }
+
+ if (undecodables == _decoders.Length)
+ {
+ // Throw an exception if all decoders cannot decode data.
+ input.Position = input.Limit; // Skip data
+ throw new ProtocolDecoderException(
+ "No appropriate message decoder: " + input.GetHexDump());
+ }
+
+ if (_currentDecoder == null)
+ {
+ // Decoder is not determined yet (i.e. we need more data)
+ return false;
+ }
+ }
+
+ result = _currentDecoder.Decode(input, output);
+ if (result == MessageDecoderResult.OK)
+ {
+ _currentDecoder = null;
+ return true;
+ }
+ else if (result == MessageDecoderResult.NEED_DATA)
+ {
+ return false;
+ }
+ else if (result == MessageDecoderResult.NOT_OK)
+ {
+ throw new ProtocolDecoderException("Message decoder returned NOT_OK.");
+ }
+ else
+ {
+ throw new Exception("Unexpected decode result (see your decode()): " + result);
+ }
+ }
+ }
+
+ private class SingletonMessageEncoderFactory : IMessageEncoderFactory
+ {
+ private readonly IMessageEncoder _encoder;
+
+ public SingletonMessageEncoderFactory(IMessageEncoder encoder)
+ {
+ if (encoder == null)
+ {
+ throw new ArgumentNullException("encoder");
+ }
+ _encoder = encoder;
+ }
+
+ public IMessageEncoder NewEncoder()
+ {
+ return _encoder;
+ }
+ }
+
+ private class SingletonMessageDecoderFactory : IMessageDecoderFactory
+ {
+ private readonly IMessageDecoder _decoder;
+
+ public SingletonMessageDecoderFactory(IMessageDecoder decoder)
+ {
+ if (decoder == null)
+ {
+ throw new ArgumentNullException("decoder");
+ }
+ _decoder = decoder;
+ }
+
+ public IMessageDecoder NewDecoder()
+ {
+ return _decoder;
+ }
+ }
+
+ private class DefaultConstructorMessageEncoderFactory : IMessageEncoderFactory
+ {
+ private readonly Type _encoderClass;
+
+ public DefaultConstructorMessageEncoderFactory(Type encoderClass)
+ {
+ if (encoderClass == null)
+ {
+ throw new ArgumentNullException("encoderClass");
+ }
+
+ if(!typeof(IMessageEncoder).IsAssignableFrom(encoderClass))
+ {
+ throw new ArgumentException("encoderClass is not assignable to MessageEncoder");
+ }
+ _encoderClass = encoderClass;
+ }
+
+ public IMessageEncoder NewEncoder()
+ {
+ try
+ {
+ return (IMessageEncoder) Activator.CreateInstance(_encoderClass);
+ }
+ catch (Exception e)
+ {
+ throw new Exception( "Failed to create a new instance of " + _encoderClass, e);
+ }
+ }
+ }
+
+ private class DefaultConstructorMessageDecoderFactory : IMessageDecoderFactory
+ {
+ private readonly Type _decoderClass;
+
+ public DefaultConstructorMessageDecoderFactory(Type decoderClass)
+ {
+ if (decoderClass == null)
+ {
+ throw new ArgumentNullException("decoderClass");
+ }
+
+ if(!typeof(IMessageDecoder).IsAssignableFrom(decoderClass))
+ {
+ throw new ArgumentException("decoderClass is not assignable to MessageDecoder");
+ }
+ _decoderClass = decoderClass;
+ }
+
+ public IMessageDecoder NewDecoder()
+ {
+ try
+ {
+ return (IMessageDecoder) Activator.CreateInstance(_decoderClass);
+ }
+ catch (Exception e)
+ {
+ throw new Exception("Failed to create a new instance of " + _decoderClass, e);
+ }
+ }
+ }
+ }
+}
+
+
+