public static LegacyOCPMessage decodeBuffer(final ByteBuffer buffer)
            throws OCPException {
        if (buffer.limit() < OCP_MIN_LENGTH) {
            // Too short to possibly be a valid message
            throw new OCPException();
        }

        Class<? extends LegacyOCPMessage> implementation;
        Constructor<? extends LegacyOCPMessage> constructor;

        short commandCode = buffer.getShort(OCP_CMD_CODE_OFFSET);
        implementation = getOCPClass(commandCode);
        if (implementation == null) {
            // Unimplemented OCP message. Try and work out what sort it was.
            switch (commandCode & OCP_COMMAND_TYPE_MASK) {
            case OCP_COMMAND_TYPE_LINK:
                throw new LinkMessageException(
                        commandCode,
                        LinkCommandUnsupported.REASON_COMMAND_CODE_UNSUPPORTED);
            case OCP_COMMAND_TYPE_CALL:
                // Extract the task IDs from the original message
                throw new CallMessageException(
                        buffer.getInt(LegacyOCPMessage.OCP_DEST_TID_OFFSET),
                        buffer.getInt(LegacyOCPMessage.OCP_ORIG_TID_OFFSET),
                        commandCode,
                        CallCommandUnsupported.REASON_COMMAND_CODE_UNSUPPORTED);
            default:
                throw new UnknownMessageTypeException();
            }
        }

        try {
            constructor = implementation.getConstructor(ByteBuffer.class);
            return constructor.newInstance(buffer);
        } catch (InvocationTargetException e) {
            // The constructor threw an exception
            if (e.getTargetException() instanceof OCPException) {
                // Propogate OCPExceptions.
                throw (OCPException) e.getTargetException();
            } else {
                // Wrap non-OCPExceptions.
                throw new OCPException(e.getTargetException());
            }
        } catch (Exception e) {
            // Attempting to call the constructor failed. Wrap in an
            // OCPException.
            throw new OCPException(e);
        }
    }