VersionSpecificRegistry.java
001 /*
002  *
003  * Licensed to the Apache Software Foundation (ASF) under one
004  * or more contributor license agreements.  See the NOTICE file
005  * distributed with this work for additional information
006  * regarding copyright ownership.  The ASF licenses this file
007  * to you under the Apache License, Version 2.0 (the
008  * "License"); you may not use this file except in compliance
009  * with the License.  You may obtain a copy of the License at
010  *
011  *   http://www.apache.org/licenses/LICENSE-2.0
012  *
013  * Unless required by applicable law or agreed to in writing,
014  * software distributed under the License is distributed on an
015  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016  * KIND, either express or implied.  See the License for the
017  * specific language governing permissions and limitations
018  * under the License.
019  *
020  */
021 package org.apache.qpid.framing;
022 
023 import org.apache.mina.common.ByteBuffer;
024 
025 import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter;
026 
027 import org.slf4j.Logger;
028 import org.slf4j.LoggerFactory;
029 
030 public class VersionSpecificRegistry
031 {
032     private static final Logger _log = LoggerFactory.getLogger(VersionSpecificRegistry.class);
033 
034     private final byte _protocolMajorVersion;
035     private final byte _protocolMinorVersion;
036 
037     private static final int DEFAULT_MAX_CLASS_ID = 200;
038     private static final int DEFAULT_MAX_METHOD_ID = 50;
039 
040     private AMQMethodBodyInstanceFactory[][] _registry = new AMQMethodBodyInstanceFactory[DEFAULT_MAX_CLASS_ID][];
041 
042     private ProtocolVersionMethodConverter _protocolVersionConverter;
043 
044     public VersionSpecificRegistry(byte major, byte minor)
045     {
046         _protocolMajorVersion = major;
047         _protocolMinorVersion = minor;
048 
049         _protocolVersionConverter = loadProtocolVersionConverters(major, minor);
050     }
051 
052     private static ProtocolVersionMethodConverter loadProtocolVersionConverters(byte protocolMajorVersion,
053         byte protocolMinorVersion)
054     {
055         try
056         {
057             Class<ProtocolVersionMethodConverter> versionMethodConverterClass =
058                 (Class<ProtocolVersionMethodConverter>Class.forName("org.apache.qpid.framing.MethodConverter_"
059                     + protocolMajorVersion + "_" + protocolMinorVersion);
060 
061             return versionMethodConverterClass.newInstance();
062 
063         }
064         catch (ClassNotFoundException e)
065         {
066             _log.warn("Could not find protocol conversion classes for " + protocolMajorVersion + "-" + protocolMinorVersion);
067             if (protocolMinorVersion != 0)
068             {
069                 protocolMinorVersion--;
070 
071                 return loadProtocolVersionConverters(protocolMajorVersion, protocolMinorVersion);
072             }
073             else if (protocolMajorVersion != 0)
074             {
075                 protocolMajorVersion--;
076 
077                 return loadProtocolVersionConverters(protocolMajorVersion, protocolMinorVersion);
078             }
079             else
080             {
081                 return null;
082             }
083 
084         }
085         catch (IllegalAccessException e)
086         {
087             throw new IllegalStateException("Unable to load protocol version converter: ", e);
088         }
089         catch (InstantiationException e)
090         {
091             throw new IllegalStateException("Unable to load protocol version converter: ", e);
092         }
093     }
094 
095     public byte getProtocolMajorVersion()
096     {
097         return _protocolMajorVersion;
098     }
099 
100     public byte getProtocolMinorVersion()
101     {
102         return _protocolMinorVersion;
103     }
104 
105     public AMQMethodBodyInstanceFactory getMethodBody(final short classID, final short methodID)
106     {
107         try
108         {
109             return _registry[classID][methodID];
110         }
111         catch (IndexOutOfBoundsException e)
112         {
113             return null;
114         }
115         catch (NullPointerException e)
116         {
117             return null;
118         }
119     }
120 
121     public void registerMethod(final short classID, final short methodID, final AMQMethodBodyInstanceFactory instanceFactory)
122     {
123         if (_registry.length <= classID)
124         {
125             AMQMethodBodyInstanceFactory[][] oldRegistry = _registry;
126             _registry = new AMQMethodBodyInstanceFactory[classID + 1][];
127             System.arraycopy(oldRegistry, 0, _registry, 0, oldRegistry.length);
128         }
129 
130         if (_registry[classID== null)
131         {
132             _registry[classID=
133                 new AMQMethodBodyInstanceFactory[(methodID > DEFAULT_MAX_METHOD_ID(methodID + 1)
134                                                                                     (DEFAULT_MAX_METHOD_ID + 1)];
135         }
136         else if (_registry[classID].length <= methodID)
137         {
138             AMQMethodBodyInstanceFactory[] oldMethods = _registry[classID];
139             _registry[classIDnew AMQMethodBodyInstanceFactory[methodID + 1];
140             System.arraycopy(oldMethods, 0, _registry[classID]0, oldMethods.length);
141         }
142 
143         _registry[classID][methodID= instanceFactory;
144 
145     }
146 
147     public AMQMethodBody get(short classID, short methodID, ByteBuffer in, long sizethrows AMQFrameDecodingException
148     {
149         AMQMethodBodyInstanceFactory bodyFactory;
150         try
151         {
152             bodyFactory = _registry[classID][methodID];
153         }
154         catch (NullPointerException e)
155         {
156             throw new AMQFrameDecodingException(null, "Class " + classID + " unknown in AMQP version "
157                 + _protocolMajorVersion + "-" + _protocolMinorVersion + " (while trying to decode class " + classID
158                 " method " + methodID + ".", e);
159         }
160         catch (IndexOutOfBoundsException e)
161         {
162             if (classID >= _registry.length)
163             {
164                 throw new AMQFrameDecodingException(null, "Class " + classID + " unknown in AMQP version "
165                     + _protocolMajorVersion + "-" + _protocolMinorVersion + " (while trying to decode class " + classID
166                     " method " + methodID + ".", e);
167 
168             }
169             else
170             {
171                 throw new AMQFrameDecodingException(null, "Method " + methodID + " unknown in AMQP version "
172                     + _protocolMajorVersion + "-" + _protocolMinorVersion + " (while trying to decode class " + classID
173                     " method " + methodID + ".", e);
174 
175             }
176         }
177 
178         if (bodyFactory == null)
179         {
180             throw new AMQFrameDecodingException(null, "Method " + methodID + " unknown in AMQP version "
181                 + _protocolMajorVersion + "-" + _protocolMinorVersion + " (while trying to decode class " + classID
182                 " method " + methodID + "."null);
183         }
184 
185         return bodyFactory.newInstancein, size);
186 
187     }
188 
189     public ProtocolVersionMethodConverter getProtocolVersionMethodConverter()
190     {
191         return _protocolVersionConverter;
192     }
193 
194     public void configure()
195     {
196         _protocolVersionConverter.configure();
197     }
198 }