protected void processPlainSection(final ExecutionContext ectx) throws Exception {
    final SectionContext sctx = ectx.sectionContext;
    final PlainSection section = (PlainSection) sctx.section;
    DataProvider provider = null;
    Query query = null;
    if (section.getDataProvider() != null) {
      provider = section.getDataProvider().getProvider(ectx.elctx);
      query = section.getDataProvider().getQuery(ectx.elctx);
    }

    if (provider != null) {
      sctx.beanIterator = provider.execute(query);
      try {
        while (sctx.beanIterator.hasNext()) {
          sctx.bean = sctx.beanIterator.next();
          ectx.elctx.setRowModel(sctx.bean);
          ectx.elctx.getVariables().put(VAR_RECORD, sctx.record);
          renderArea(ectx, section.getTemplate(), -1);
          for (SectionEventListener listener : sctx.sectionListeners) {
            listener.afterRecord(ectx);
          }
          sctx.recordFirstRow = ectx.getNewRowNum();
          sctx.record++;
        }
      } finally {
        sctx.beanIterator.close();
        sctx.beanIterator = null;
        sctx.bean = null;
      }
    } else {
      renderArea(ectx, section.getTemplate(), -1);
    }
  }
  protected void processCompositeSection(final ExecutionContext ectx) throws Exception {
    final SectionContext sctx = ectx.sectionContext;
    final CompositeSection section = (CompositeSection) sctx.section;
    DataProvider provider = null;
    Query query = null;
    if (section.getDataProvider() != null) {
      provider = section.getDataProvider().getProvider(ectx.elctx);
      query = section.getDataProvider().getQuery(ectx.elctx);
    }

    final ProviderUsage providerUsage = section.getProviderUsage();
    if (provider != null && providerUsage != ProviderUsage.DECLARE_ONLY) {
      sctx.gm =
          new GroupManager(section.getGroups()) {
            public void renderCurrentGroup(final ExecutionContext ctx) throws Exception {
              renderGroup(ctx, getCurrentGroup());
            }
          };
      sctx.beanIterator = provider.execute(query);
      try {
        while (sctx.beanIterator.hasNext()) {
          sctx.bean =
              ProviderUsage.PREFETCH_RECORDS == providerUsage
                  ? sctx.beanIterator.readAhead()
                  : sctx.beanIterator.next();
          ectx.elctx.setRowModel(sctx.bean);
          ectx.elctx.getVariables().put(VAR_RECORD, sctx.record);
          sctx.gm.initRecord(ectx, sctx.bean);
          for (final Section childSection : section.getSections()) {
            processSection(ectx, childSection);
          }
          sctx.gm.finalizeRecord(ectx);
          for (final SectionEventListener listener : sctx.sectionListeners) {
            listener.afterRecord(ectx);
          }
          sctx.recordFirstRow = ectx.getNewRowNum();
          sctx.record++;
        }
      } finally {
        sctx.beanIterator.close();
        sctx.beanIterator = null;
        sctx.bean = null;
      }
      sctx.gm.finalizeAllGroups(ectx);
      sctx.gm = null;
    } else {
      sctx.beanIterator = provider != null ? provider.execute(query) : null;
      try {
        for (final Section childSection : section.getSections()) {
          processSection(ectx, childSection);
        }
      } finally {
        if (sctx.beanIterator != null) {
          sctx.beanIterator.close();
          sctx.beanIterator = null;
        }
      }
    }
  }
  protected void processGroupingSection(final ExecutionContext ectx) throws Exception {
    final SectionContext sctx = ectx.sectionContext;
    final GroupingSection section = (GroupingSection) sctx.section;
    DataProvider provider = null;
    Query query = null;
    if (section.getDataProvider() != null) {
      provider = section.getDataProvider().getProvider(ectx.elctx);
      query = section.getDataProvider().getQuery(ectx.elctx);
    }

    if (provider != null) {
      sctx.gm =
          new GroupManager(section.getGroups()) {
            public void renderCurrentGroup(final ExecutionContext ctx) throws Exception {
              renderGroup(ctx, getCurrentGroup());
            }
          };
      sctx.beanIterator = provider.execute(query);
      try {
        while (sctx.beanIterator.hasNext()) {
          sctx.bean = sctx.beanIterator.next();
          ectx.elctx.setRowModel(sctx.bean);
          ectx.elctx.getVariables().put(VAR_RECORD, sctx.record);
          sctx.gm.initRecord(ectx, sctx.bean);
          renderArea(ectx, section.getRowTemplate(), -1);
          sctx.gm.finalizeRecord(ectx);
          for (final SectionEventListener listener : sctx.sectionListeners) {
            listener.afterRecord(ectx);
          }
          sctx.recordFirstRow = ectx.getNewRowNum();
          sctx.record++;
        }
      } finally {
        sctx.beanIterator.close();
        sctx.beanIterator = null;
        sctx.bean = null;
      }
      sctx.gm.finalizeAllGroups(ectx);
      sctx.gm = null;
    } else {
      renderArea(ectx, section.getRowTemplate(), -1);
    }
  }
  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);
  }