001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software GmbH & Co. KG, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.jsp;
029
030import org.opencms.file.CmsResource;
031import org.opencms.i18n.CmsMessageContainer;
032import org.opencms.xml.CmsXmlUtils;
033import org.opencms.xml.I_CmsXmlDocument;
034
035import java.util.List;
036import java.util.Locale;
037
038import javax.servlet.jsp.JspException;
039import javax.servlet.jsp.JspTagException;
040import javax.servlet.jsp.tagext.Tag;
041import javax.servlet.jsp.tagext.TagSupport;
042
043/**
044 * Used to loop through the element values of an XML content item.<p>
045 *
046 * @since 6.0.0
047 */
048public class CmsJspTagContentLoop extends TagSupport implements I_CmsXmlContentContainer {
049
050    /** Serial version UID required for safe serialization. */
051    private static final long serialVersionUID = 8832749526732064836L;
052
053    /** Reference to the parent 'contentload' tag. */
054    private transient I_CmsXmlContentContainer m_container;
055
056    /** Reference to the looped content element. */
057    private transient I_CmsXmlDocument m_content;
058
059    /** Name of the current element (including the index). */
060    private String m_currentElement;
061
062    /** Name of the content node element to show. */
063    private String m_element;
064
065    /** Indicates if this is the first content iteration loop. */
066    private boolean m_firstLoop;
067
068    /** Index of the content node element to show. */
069    private int m_index = -1;
070
071    /** Reference to the currently selected locale. */
072    private Locale m_locale;
073
074    /**
075     * Empty constructor, required for JSP tags.<p>
076     */
077    public CmsJspTagContentLoop() {
078
079        super();
080    }
081
082    /**
083     * Constructor used when using <code>contentloop</code> from scriptlet code.<p>
084     *
085     * @param container the parent content container that provides the content element to loop
086     * @param element the element to loop in the content
087     */
088    public CmsJspTagContentLoop(I_CmsXmlContentContainer container, String element) {
089
090        m_element = element;
091        init(container);
092    }
093
094    /**
095     * @see javax.servlet.jsp.tagext.TagSupport#doAfterBody()
096     */
097    @Override
098    public int doAfterBody() {
099
100        if (hasMoreResources()) {
101            // one more element with the same name is available, loop again
102            return EVAL_BODY_AGAIN;
103        }
104        // no more elements with this name available, finish the loop
105        return SKIP_BODY;
106    }
107
108    /**
109     * @see javax.servlet.jsp.tagext.Tag#doEndTag()
110     */
111    @Override
112    public int doEndTag() {
113
114        release();
115        return EVAL_PAGE;
116    }
117
118    /**
119     * @see javax.servlet.jsp.tagext.Tag#doStartTag()
120     */
121    @Override
122    public int doStartTag() throws JspException {
123
124        // get a reference to the parent "content container" class
125        Tag ancestor = findAncestorWithClass(this, I_CmsXmlContentContainer.class);
126        if (ancestor == null) {
127            CmsMessageContainer errMsgContainer = Messages.get().container(
128                Messages.ERR_PARENTLESS_TAG_1,
129                "contentloop");
130            String msg = Messages.getLocalizedMessage(errMsgContainer, pageContext);
131            throw new JspTagException(msg);
132        }
133        I_CmsXmlContentContainer container = (I_CmsXmlContentContainer)ancestor;
134
135        // initialize the content
136        init(container);
137
138        if (hasMoreResources()) {
139            // selected element is available at last once in content
140            return EVAL_BODY_INCLUDE;
141        } else {
142            // no value available for the selected element name, so we skip the whole body
143            return SKIP_BODY;
144        }
145    }
146
147    /**
148     * @see org.opencms.jsp.I_CmsXmlContentContainer#getCollectorName()
149     */
150    public String getCollectorName() {
151
152        return m_container.getCollectorName();
153    }
154
155    /**
156     * @see org.opencms.jsp.I_CmsXmlContentContainer#getCollectorParam()
157     */
158    public String getCollectorParam() {
159
160        return m_container.getCollectorParam();
161    }
162
163    /**
164     * @see org.opencms.jsp.I_CmsXmlContentContainer#getCollectorResult()
165     */
166    public List<CmsResource> getCollectorResult() {
167
168        return m_container.getCollectorResult();
169    }
170
171    /**
172     * Returns the name of the content node element to show.<p>
173     *
174     * @return the name of the content node element to show
175     */
176    public String getElement() {
177
178        return (m_element != null) ? m_element : "";
179    }
180
181    /**
182     * @see org.opencms.jsp.I_CmsResourceContainer#getResource()
183     */
184    public CmsResource getResource() {
185
186        return m_content.getFile();
187    }
188
189    /**
190     * @see org.opencms.jsp.I_CmsXmlContentContainer#getResourceName()
191     */
192    public String getResourceName() {
193
194        return m_container.getResourceName();
195    }
196
197    /**
198     * @see org.opencms.jsp.I_CmsXmlContentContainer#getXmlDocument()
199     */
200    public I_CmsXmlDocument getXmlDocument() {
201
202        return m_content;
203    }
204
205    /**
206     * @see org.opencms.jsp.I_CmsXmlContentContainer#getXmlDocumentElement()
207     */
208    public String getXmlDocumentElement() {
209
210        return m_currentElement;
211    }
212
213    /**
214     * @see org.opencms.jsp.I_CmsXmlContentContainer#getXmlDocumentLocale()
215     */
216    public Locale getXmlDocumentLocale() {
217
218        return m_locale;
219    }
220
221    /**
222     * @see org.opencms.jsp.I_CmsResourceContainer#hasMoreContent()
223     */
224    @Deprecated
225    public boolean hasMoreContent() {
226
227        return hasMoreResources();
228    }
229
230    /**
231     * @see org.opencms.jsp.I_CmsXmlContentContainer#hasMoreResources()
232     */
233    public boolean hasMoreResources() {
234
235        if (m_firstLoop) {
236            m_firstLoop = false;
237        } else {
238            m_index++;
239        }
240        if (m_content.hasValue(m_element, m_locale, m_index)) {
241            m_currentElement = CmsXmlUtils.createXpath(m_element, m_index + 1);
242            // one more element with the same name is available, loop again
243            return true;
244        } else {
245            // no more elements with this name available, finish the loop
246            return false;
247        }
248    }
249
250    /**
251     * @see org.opencms.jsp.I_CmsXmlContentContainer#isPreloader()
252     */
253    public boolean isPreloader() {
254
255        return m_container.isPreloader();
256    }
257
258    /**
259     * @see javax.servlet.jsp.tagext.Tag#release()
260     */
261    @Override
262    public void release() {
263
264        m_element = null;
265        m_currentElement = null;
266        m_content = null;
267        m_locale = null;
268        m_container = null;
269        m_index = 0;
270        super.release();
271    }
272
273    /**
274     * Sets the name of the content node element to show.<p>
275     *
276     * @param element the name of the content node element to show
277     */
278    public void setElement(String element) {
279
280        m_element = element;
281    }
282
283    /**
284     * Initializes this content loop tag.<p>
285     *
286     * @param container the parent content container that provides the content element to loop
287     */
288    protected void init(I_CmsXmlContentContainer container) {
289
290        m_container = container;
291
292        // append to parent element name (required for nested schemas)
293        m_element = CmsXmlUtils.concatXpath(m_container.getXmlDocumentElement(), m_element);
294
295        // get loaded content from parent <contentload> tag
296        m_content = m_container.getXmlDocument();
297        m_locale = m_container.getXmlDocumentLocale();
298        m_index = 0;
299        m_currentElement = null;
300
301        // the next loop is the first loop
302        m_firstLoop = true;
303    }
304}