private void generateGroupEncoderClassHeader(
        final StringBuilder sb,
        final String groupName,
        final String parentMessageClassName,
        final FieldPrecedenceModel fieldPrecedenceModel,
        final Token groupToken,
        final List<Token> tokens,
        final List<Token> subGroupTokens,
        final int index,
        final String ind)
    {
        final int dimensionHeaderSize = tokens.get(index + 1).encodedLength();

        generateGroupEncoderClassDeclaration(
            sb,
            groupName,
            parentMessageClassName,
            findSubGroupNames(subGroupTokens),
            ind,
            dimensionHeaderSize);

        final int blockLength = tokens.get(index).encodedLength();
        final Token blockLengthToken = Generators.findFirst("blockLength", tokens, index);
        final Token numInGroupToken = Generators.findFirst("numInGroup", tokens, index);

        final PrimitiveType blockLengthType = blockLengthToken.encoding().primitiveType();
        final String blockLengthOffset = "limit + " + blockLengthToken.offset();
        final String blockLengthValue = Integer.toString(blockLength);
        final String blockLengthPut = generatePut(
            blockLengthType, blockLengthOffset, blockLengthValue, byteOrderString(blockLengthToken.encoding()));

        final PrimitiveType numInGroupType = numInGroupToken.encoding().primitiveType();

        final PrimitiveType numInGroupTypeCast = PrimitiveType.UINT32 == numInGroupType ?
            PrimitiveType.INT32 : numInGroupType;
        final String numInGroupOffset = "limit + " + numInGroupToken.offset();
        final String numInGroupValue = "count";
        final String numInGroupPut = generatePut(
            numInGroupTypeCast, numInGroupOffset, numInGroupValue, byteOrderString(numInGroupToken.encoding()));

        new Formatter(sb).format("\n" +
            ind + "    public void wrap(final %2$s buffer, final int count)\n" +
            ind + "    {\n" +
            ind + "        if (count < %3$d || count > %4$d)\n" +
            ind + "        {\n" +
            ind + "            throw new IllegalArgumentException(\"count outside allowed range: count=\" + count);\n" +
            ind + "        }\n\n" +
            ind + "        if (buffer != this.buffer)\n" +
            ind + "        {\n" +
            ind + "            this.buffer = buffer;\n" +
            ind + "        }\n\n" +
            ind + "        index = 0;\n" +
            ind + "        this.count = count;\n" +
            ind + "        final int limit = parentMessage.limit();\n" +
            ind + "        initialLimit = limit;\n" +
            ind + "        parentMessage.limit(limit + HEADER_SIZE);\n" +
            ind + "        %5$s;\n" +
            ind + "        %6$s;\n" +
            ind + "    }\n\n",
            parentMessageClassName,
            mutableBuffer,
            numInGroupToken.encoding().applicableMinValue().longValue(),
            numInGroupToken.encoding().applicableMaxValue().longValue(),
            blockLengthPut,
            numInGroupPut);

        generateAccessOrderListenerMethodForNextGroupElement(sb, fieldPrecedenceModel, ind + "    ", groupToken);
        generateAccessOrderListenerMethodForResetGroupCount(sb, fieldPrecedenceModel, ind + "    ", groupToken);

        sb.append(ind).append("    public ").append(encoderName(groupName)).append(" next()\n")
            .append(ind).append("    {\n")
            .append(generateAccessOrderListenerCall(fieldPrecedenceModel, ind + "        ", "onNextElementAccessed"))
            .append(ind).append("        if (index >= count)\n")
            .append(ind).append("        {\n")
            .append(ind).append("            throw new java.util.NoSuchElementException();\n")
            .append(ind).append("        }\n\n")
            .append(ind).append("        offset = parentMessage.limit();\n")
            .append(ind).append("        parentMessage.limit(offset + sbeBlockLength());\n")
            .append(ind).append("        ++index;\n\n")
            .append(ind).append("        return this;\n")
            .append(ind).append("    }\n\n");

        final String countOffset = "initialLimit + " + numInGroupToken.offset();
        final String resetCountPut = generatePut(
            numInGroupTypeCast, countOffset, numInGroupValue, byteOrderString(numInGroupToken.encoding()));

        sb.append(ind).append("    public int resetCountToIndex()\n")
            .append(ind).append("    {\n")
            .append(generateAccessOrderListenerCall(fieldPrecedenceModel, ind + "        ", "onResetCountToIndex"))
            .append(ind).append("        count = index;\n")
            .append(ind).append("        ").append(resetCountPut).append(";\n\n")
            .append(ind).append("        return count;\n")
            .append(ind).append("    }\n");

        final String numInGroupJavaTypeName = javaTypeName(numInGroupType);
        final String numInGroupMinValue = generateLiteral(
            numInGroupType, numInGroupToken.encoding().applicableMinValue().toString());
        generatePrimitiveFieldMetaMethod(sb, ind, numInGroupJavaTypeName, "count", "Min", numInGroupMinValue);
        final String numInGroupMaxValue = generateLiteral(
            numInGroupType, numInGroupToken.encoding().applicableMaxValue().toString());
        generatePrimitiveFieldMetaMethod(sb, ind, numInGroupJavaTypeName, "count", "Max", numInGroupMaxValue);

        sb.append("\n")
            .append(ind).append("    public static int sbeHeaderSize()\n")
            .append(ind).append("    {\n")
            .append(ind).append("        return HEADER_SIZE;\n")
            .append(ind).append("    }\n");

        sb.append("\n")
            .append(ind).append("    public static int sbeBlockLength()\n")
            .append(ind).append("    {\n")
            .append(ind).append("        return ").append(blockLength).append(";\n")
            .append(ind).append("    }\n");

        if (null != fieldPrecedenceModel)
        {
            sb.append("\n")
                .append(ind).append("    private int codecState()\n")
                .append(ind).append("    {\n")
                .append(ind).append("        return parentMessage.codecState();\n")
                .append(ind).append("    }\n");

            sb.append("\n")
                .append(ind).append("    private void codecState(final int newState)\n")
                .append(ind).append("    {\n")
                .append(ind).append("        parentMessage.codecState(newState);\n")
                .append(ind).append("    }\n");
        }
    }
\n");
        sb.append("     * The states in which a encoder/decoder/codec can live.\n");
        sb.append("     *\n");
        sb.append("     * <p>The state machine diagram below, encoded in the dot language, describes\n");
        sb.append("     * the valid state transitions according to the order in which fields may be\n");
        sb.append("     * accessed safely. Tools such as PlantUML and Graphviz can render it.\n");
        sb.append("     *\n");
        sb.append("     * <pre>{@code\n");
        fieldPrecedenceModel.generateGraph(sb, "     *   ");
        sb.append("     * }</pre>\n");
        sb.append("
sbe-tool/src/main/java/uk/co/real_logic/sbe/generation/java/JavaGenerator.java