/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ package org.apache.qpid.framing; import org.apache.mina.common.ByteBuffer; import org.apache.qpid.framing.abstraction.ProtocolVersionMethodConverter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class VersionSpecificRegistry { private static final Logger _log = LoggerFactory.getLogger(VersionSpecificRegistry.class); private final byte _protocolMajorVersion; private final byte _protocolMinorVersion; private static final int DEFAULT_MAX_CLASS_ID = 200; private static final int DEFAULT_MAX_METHOD_ID = 50; private AMQMethodBodyInstanceFactory[][] _registry = new AMQMethodBodyInstanceFactory[DEFAULT_MAX_CLASS_ID][]; private ProtocolVersionMethodConverter _protocolVersionConverter; public VersionSpecificRegistry(byte major, byte minor) { _protocolMajorVersion = major; _protocolMinorVersion = minor; _protocolVersionConverter = loadProtocolVersionConverters(major, minor); } private static ProtocolVersionMethodConverter loadProtocolVersionConverters(byte protocolMajorVersion, byte protocolMinorVersion) { try { Class versionMethodConverterClass = (Class) Class.forName("org.apache.qpid.framing.MethodConverter_" + protocolMajorVersion + "_" + protocolMinorVersion); return versionMethodConverterClass.newInstance(); } catch (ClassNotFoundException e) { _log.warn("Could not find protocol conversion classes for " + protocolMajorVersion + "-" + protocolMinorVersion); if (protocolMinorVersion != 0) { protocolMinorVersion--; return loadProtocolVersionConverters(protocolMajorVersion, protocolMinorVersion); } else if (protocolMajorVersion != 0) { protocolMajorVersion--; return loadProtocolVersionConverters(protocolMajorVersion, protocolMinorVersion); } else { return null; } } catch (IllegalAccessException e) { throw new IllegalStateException("Unable to load protocol version converter: ", e); } catch (InstantiationException e) { throw new IllegalStateException("Unable to load protocol version converter: ", e); } } public byte getProtocolMajorVersion() { return _protocolMajorVersion; } public byte getProtocolMinorVersion() { return _protocolMinorVersion; } public AMQMethodBodyInstanceFactory getMethodBody(final short classID, final short methodID) { try { return _registry[classID][methodID]; } catch (IndexOutOfBoundsException e) { return null; } catch (NullPointerException e) { return null; } } public void registerMethod(final short classID, final short methodID, final AMQMethodBodyInstanceFactory instanceFactory) { if (_registry.length <= classID) { AMQMethodBodyInstanceFactory[][] oldRegistry = _registry; _registry = new AMQMethodBodyInstanceFactory[classID + 1][]; System.arraycopy(oldRegistry, 0, _registry, 0, oldRegistry.length); } if (_registry[classID] == null) { _registry[classID] = new AMQMethodBodyInstanceFactory[(methodID > DEFAULT_MAX_METHOD_ID) ? (methodID + 1) : (DEFAULT_MAX_METHOD_ID + 1)]; } else if (_registry[classID].length <= methodID) { AMQMethodBodyInstanceFactory[] oldMethods = _registry[classID]; _registry[classID] = new AMQMethodBodyInstanceFactory[methodID + 1]; System.arraycopy(oldMethods, 0, _registry[classID], 0, oldMethods.length); } _registry[classID][methodID] = instanceFactory; } public AMQMethodBody get(short classID, short methodID, ByteBuffer in, long size) throws AMQFrameDecodingException { AMQMethodBodyInstanceFactory bodyFactory; try { bodyFactory = _registry[classID][methodID]; } catch (NullPointerException e) { throw new AMQFrameDecodingException(null, "Class " + classID + " unknown in AMQP version " + _protocolMajorVersion + "-" + _protocolMinorVersion + " (while trying to decode class " + classID + " method " + methodID + ".", e); } catch (IndexOutOfBoundsException e) { if (classID >= _registry.length) { throw new AMQFrameDecodingException(null, "Class " + classID + " unknown in AMQP version " + _protocolMajorVersion + "-" + _protocolMinorVersion + " (while trying to decode class " + classID + " method " + methodID + ".", e); } else { throw new AMQFrameDecodingException(null, "Method " + methodID + " unknown in AMQP version " + _protocolMajorVersion + "-" + _protocolMinorVersion + " (while trying to decode class " + classID + " method " + methodID + ".", e); } } if (bodyFactory == null) { throw new AMQFrameDecodingException(null, "Method " + methodID + " unknown in AMQP version " + _protocolMajorVersion + "-" + _protocolMinorVersion + " (while trying to decode class " + classID + " method " + methodID + ".", null); } return bodyFactory.newInstance( in, size); } public ProtocolVersionMethodConverter getProtocolVersionMethodConverter() { return _protocolVersionConverter; } public void configure() { _protocolVersionConverter.configure(); } }