content: /*
   * This library is part of OpenCms -
   * the Open Source Content Management System
   *
   * Copyright (c) Alkacon Software GmbH & Co. KG (https://www.alkacon.com)
   *
   * This library is free software; you can redistribute it and/or
   * modify it under the terms of the GNU Lesser General Public
   * License as published by the Free Software Foundation; either
   * version 2.1 of the License, or (at your option) any later version.
   *
   * This library is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   * Lesser General Public License for more details.
   *
   * For further information about Alkacon Software GmbH & Co. KG, please see the
   * company website: https://www.alkacon.com
   *
   * For further information about OpenCms, please see the
   * project website: https://www.opencms.org
   *
   * You should have received a copy of the GNU Lesser General Public
   * License along with this library; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
   */
  
  package org.opencms.jsp;
  
  import org.opencms.file.CmsResource;
  import org.opencms.i18n.CmsMessageContainer;
  import org.opencms.xml.CmsXmlUtils;
  import org.opencms.xml.I_CmsXmlDocument;
  
  import java.util.List;
  import java.util.Locale;
  
  import javax.servlet.jsp.JspException;
  import javax.servlet.jsp.JspTagException;
  import javax.servlet.jsp.tagext.Tag;
  import javax.servlet.jsp.tagext.TagSupport;
  
  /**
   * Used to loop through the element values of an XML content item.<p>
   *
   * @since 6.0.0
   */
  public class CmsJspTagContentLoop extends TagSupport implements I_CmsXmlContentContainer {
  
      /** Serial version UID required for safe serialization. */
      private static final long serialVersionUID = 8832749526732064836L;
  
      /** Reference to the parent 'contentload' tag. */
      private transient I_CmsXmlContentContainer m_container;
  
      /** Reference to the looped content element. */
      private transient I_CmsXmlDocument m_content;
  
      /** Name of the current element (including the index). */
      private String m_currentElement;
  
      /** Name of the content node element to show. */
      private String m_element;
  
      /** Indicates if this is the first content iteration loop. */
      private boolean m_firstLoop;
  
      /** Index of the content node element to show. */
      private int m_index = -1;
  
      /** Reference to the currently selected locale. */
      private Locale m_locale;
  
      /**
       * Empty constructor, required for JSP tags.<p>
       */
      public CmsJspTagContentLoop() {
  
          super();
      }
  
      /**
       * Constructor used when using <code>contentloop</code> from scriptlet code.<p>
       *
       * @param container the parent content container that provides the content element to loop
       * @param element the element to loop in the content
       */
      public CmsJspTagContentLoop(I_CmsXmlContentContainer container, String element) {
  
          m_element = element;
          init(container);
      }
  
      /**
       * @see javax.servlet.jsp.tagext.TagSupport#doAfterBody()
       */
      @Override
      public int doAfterBody() {
  
          if (hasMoreResources()) {
              // one more element with the same name is available, loop again
              return EVAL_BODY_AGAIN;
          }
          // no more elements with this name available, finish the loop
          return SKIP_BODY;
      }
  
      /**
       * @see javax.servlet.jsp.tagext.Tag#doEndTag()
       */
      @Override
      public int doEndTag() {
  
          release();
          return EVAL_PAGE;
      }
  
      /**
       * @see javax.servlet.jsp.tagext.Tag#doStartTag()
       */
      @Override
      public int doStartTag() throws JspException {
  
          // get a reference to the parent "content container" class
          Tag ancestor = findAncestorWithClass(this, I_CmsXmlContentContainer.class);
          if (ancestor == null) {
              CmsMessageContainer errMsgContainer = Messages.get().container(
                  Messages.ERR_PARENTLESS_TAG_1,
                  "contentloop");
              String msg = Messages.getLocalizedMessage(errMsgContainer, pageContext);
              throw new JspTagException(msg);
          }
          I_CmsXmlContentContainer container = (I_CmsXmlContentContainer)ancestor;
  
          // initialize the content
          init(container);
  
          if (hasMoreResources()) {
              // selected element is available at last once in content
              return EVAL_BODY_INCLUDE;
          } else {
              // no value available for the selected element name, so we skip the whole body
              return SKIP_BODY;
          }
      }
  
      /**
       * @see org.opencms.jsp.I_CmsXmlContentContainer#getCollectorName()
       */
      public String getCollectorName() {
  
          return m_container.getCollectorName();
      }
  
      /**
       * @see org.opencms.jsp.I_CmsXmlContentContainer#getCollectorParam()
       */
      public String getCollectorParam() {
  
          return m_container.getCollectorParam();
      }
  
      /**
       * @see org.opencms.jsp.I_CmsXmlContentContainer#getCollectorResult()
       */
      public List<CmsResource> getCollectorResult() {
  
          return m_container.getCollectorResult();
      }
  
      /**
       * Returns the name of the content node element to show.<p>
       *
       * @return the name of the content node element to show
       */
      public String getElement() {
  
          return (m_element != null) ? m_element : "";
      }
  
      /**
       * @see org.opencms.jsp.I_CmsResourceContainer#getResource()
       */
      public CmsResource getResource() {
  
          return m_content.getFile();
      }
  
      /**
       * @see org.opencms.jsp.I_CmsXmlContentContainer#getResourceName()
       */
      public String getResourceName() {
  
          return m_container.getResourceName();
      }
  
      /**
       * @see org.opencms.jsp.I_CmsXmlContentContainer#getXmlDocument()
       */
      public I_CmsXmlDocument getXmlDocument() {
  
          return m_content;
      }
  
      /**
       * @see org.opencms.jsp.I_CmsXmlContentContainer#getXmlDocumentElement()
       */
      public String getXmlDocumentElement() {
  
          return m_currentElement;
      }
  
      /**
       * @see org.opencms.jsp.I_CmsXmlContentContainer#getXmlDocumentLocale()
       */
      public Locale getXmlDocumentLocale() {
  
          return m_locale;
      }
  
      /**
       * @see org.opencms.jsp.I_CmsResourceContainer#hasMoreContent()
       */
      @Deprecated
      public boolean hasMoreContent() {
  
          return hasMoreResources();
      }
  
      /**
       * @see org.opencms.jsp.I_CmsXmlContentContainer#hasMoreResources()
       */
      public boolean hasMoreResources() {
  
          if (m_firstLoop) {
              m_firstLoop = false;
          } else {
              m_index++;
          }
          if (m_content.hasValue(m_element, m_locale, m_index)) {
              m_currentElement = CmsXmlUtils.createXpath(m_element, m_index + 1);
              // one more element with the same name is available, loop again
              return true;
          } else {
              // no more elements with this name available, finish the loop
              return false;
          }
      }
  
      /**
       * @see org.opencms.jsp.I_CmsXmlContentContainer#isPreloader()
       */
      public boolean isPreloader() {
  
          return m_container.isPreloader();
      }
  
      /**
       * @see javax.servlet.jsp.tagext.Tag#release()
       */
      @Override
      public void release() {
  
          m_element = null;
          m_currentElement = null;
          m_content = null;
          m_locale = null;
          m_container = null;
          m_index = 0;
          super.release();
      }
  
      /**
       * Sets the name of the content node element to show.<p>
       *
       * @param element the name of the content node element to show
       */
      public void setElement(String element) {
  
          m_element = element;
      }
  
      /**
       * Initializes this content loop tag.<p>
       *
       * @param container the parent content container that provides the content element to loop
       */
      protected void init(I_CmsXmlContentContainer container) {
  
          m_container = container;
  
          // append to parent element name (required for nested schemas)
          m_element = CmsXmlUtils.concatXpath(m_container.getXmlDocumentElement(), m_element);
  
          // get loaded content from parent <contentload> tag
          m_content = m_container.getXmlDocument();
          m_locale = m_container.getXmlDocumentLocale();
          m_index = 0;
          m_currentElement = null;
  
          // the next loop is the first loop
          m_firstLoop = true;
      }
  }