Open Source Repository

Home /jodd/jodd-3.3.2 | Repository Home



jodd/servlet/tag/LoopingTagSupport.java
// Copyright (c) 2003-2012, Jodd Team (jodd.org). All Rights Reserved.

package jodd.servlet.tag;

import jodd.util.LoopIterator;

import javax.servlet.jsp.tagext.SimpleTagSupport;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.JspException;

/**
 * Support for looping tags.
 */
public abstract class LoopingTagSupport extends SimpleTagSupport {

  protected int start;
  protected int end;
  protected int step = 1;
  protected String status;
  protected int modulus = 2;

  // ---------------------------------------------------------------- attributes

  /**
   * Sets the first loop value (inclusive).
   */
  public void setStart(int start) {
    this.start = start;
  }

  /**
   * Sets the end loop value (inclusive).
   */
  public void setEnd(int end) {
    this.end = end;
  }

  /**
   * Specifies the loop step. If step is 0, it will be set to +1 or -1,
   * depending on start and end values.
   */
  public void setStep(int step) {
    this.step = step;
  }

  /**
   * Specifies {@link jodd.util.LoopIterator status} variable name. If omitted, status will not be used.
   */
  public void setStatus(String status) {
    this.status = status;
  }

  /**
   * Specifies modulus value for the looping status.
   */
  public void setModulus(int modulus) {
    this.modulus = modulus;
  }


  // ---------------------------------------------------------------- helper methods

  /**
   * Shorter variant of {@link #prepareStepDirection(boolean, boolean)}.
   */
  protected void prepareStepDirection() {
    if (step == 0) {
      step = (start <= end: -1;
    }
  }

  /**
   * Prepares step value. If step is 0, it will be set to +1 or -1, depending on start and end value.
   <p>
   * If autoDirection flag is <code>true</code> then it is assumed that step is positive,
   * and that direction (step sign) should be detected from start and end value.
   <p>
   * If checkDirection flag is <code>true</code> than it checks loop direction (step sign) based on
   * start and end value. Throws an exception if direction is invalid.
   * If autoDirection is set, direction checking is skipped.
   */
  protected void prepareStepDirection(boolean autoDirection, boolean checkDirection) {
    if (step == 0) {
      step = (start <= end: -1;
      return;
    }
    if (autoDirection == true) {
      if (step < 0) {
        throw new IllegalArgumentException("Step value can't be negative: " + step);
      }
      if (start > end) {
        step = -step;
      }
      return;
    }
    if (checkDirection == true) {
      if (start < end) {
        if (step < 0) {
          throw new IllegalArgumentException("Negative step value for increasing loop.");
        }
        return;
      }
      if (start > end) {
        if (step > 0) {
          throw new IllegalArgumentException("Positive step value for decreasing loop.");
        }
      }
    }
  }


  /**
   * Loops body.
   */
  protected void loopBody() throws JspException {
    JspFragment body = getJspBody();
    if (body == null) {
      return;
    }

    LoopIterator loopIterator = new LoopIterator(start, end, step, modulus);
    if (status != null) {
      getJspContext().setAttribute(status, loopIterator);
    }
    while (loopIterator.next()) {
      TagUtil.invokeBody(body);
    }
    if (status != null) {
      getJspContext().removeAttribute(status);
    }
  }
}