protected void processSection(final ExecutionContext ectx, final Section section)
      throws Exception {
    if (!section.isRendered()) return;

    final Object prevBean = ectx.elctx.getRowModel();
    final Object prevRecord = ectx.elctx.getVariables().get(VAR_RECORD);
    final int firstRow = ectx.getNewRowNum();
    ectx.sectionContext = new SectionContext(ectx.sectionContext, section, firstRow, ectx.elctx);

    for (final SectionEventListener listener : ectx.sectionContext.sectionListeners) {
      listener.beforeSection(ectx);
    }
    if (section.isRendered()) {
      if (section instanceof CompositeSection) {
        processCompositeSection(ectx);
      } else if (section instanceof PlainSection) {
        processPlainSection(ectx);
      } else if (section instanceof GroupingSection) {
        processGroupingSection(ectx);
      } else throw new RuntimeException("Unsupported section type: " + section.getClass());

      final int lastRow = ectx.getLastRowNum();
      if (section.isHidden()) {
        for (int i = firstRow; i <= lastRow; i++) {
          ectx.wsheet.getRow(i).setZeroHeight(true);
        }
      }
      if (section.isCollapsible() && lastRow > firstRow) {
        ectx.wsheet.groupRow(firstRow, lastRow);
        ectx.wsheet.setRowGroupCollapsed(firstRow, section.isCollapsed());
      }
    }
    for (final SectionEventListener listener : ectx.sectionContext.sectionListeners) {
      listener.afterSection(ectx);
    }

    ectx.history.put(ectx.sectionContext.section.getId(), ectx.sectionContext);
    ectx.sectionContext = ectx.sectionContext.parent;
    ectx.elctx.setRowModel(prevBean);
    ectx.elctx.getVariables().put(VAR_RECORD, prevRecord);
  }