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, 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.util;
029
030import org.opencms.file.CmsObject;
031import org.opencms.file.CmsResource;
032import org.opencms.jsp.CmsJspNavBuilder;
033import org.opencms.jsp.CmsJspNavElement;
034import org.opencms.jsp.CmsJspTagNavigation;
035import org.opencms.main.CmsException;
036import org.opencms.util.CmsCollectionsGenericWrapper;
037
038import java.util.ArrayList;
039import java.util.List;
040import java.util.Locale;
041import java.util.Map;
042
043import org.apache.commons.collections.Transformer;
044
045/**
046 * Allows access to the OpenCms navigation information in combination with the
047 * <code>&lt;cms:navigation&gt;</code> tag.<p>
048 *
049 * @since 8.0
050 *
051 * @see org.opencms.jsp.CmsJspTagContentAccess
052 */
053public class CmsJspNavigationBean {
054
055    /**
056     * Provides a Map with Booleans that
057     * indicate if the given URI is the currently active element in the navigation.<p>
058     */
059    public class CmsIsActiveTransformer implements Transformer {
060
061        /**
062         * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
063         */
064        public Object transform(Object input) {
065
066            String resourceName = (String)input;
067            Boolean result = Boolean.FALSE;
068            if (CmsResource.isFolder(resourceName)) {
069                try {
070                    CmsResource defaultFile = m_cms.readDefaultFile(resourceName);
071                    if ((defaultFile != null)
072                        && m_cms.getRequestContext().getSitePath(defaultFile).equals(
073                            m_cms.getRequestContext().getUri())) {
074                        result = Boolean.TRUE;
075                    }
076                } catch (@SuppressWarnings("unused") CmsException e) {
077                    // error reading resource, result is false
078                }
079            } else {
080                result = Boolean.valueOf(m_cms.getRequestContext().getUri().equals(resourceName));
081            }
082
083            return result;
084        }
085    }
086
087    /**
088     * Provides a Map with Booleans that
089     * indicate if the given navigation URI is a parent element of the current URI.<p>
090     */
091    public class CmsIsParentTransformer implements Transformer {
092
093        /**
094         * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
095         */
096        public Object transform(Object input) {
097
098            String resourceName = null;
099            if (input instanceof CmsJspNavElement) {
100                CmsJspNavElement navElement = (CmsJspNavElement)input;
101                if (navElement.getResource() != null) {
102                    resourceName = m_cms.getSitePath(navElement.getResource());
103                } else {
104                    resourceName = navElement.getResourceName();
105                }
106            } else {
107                resourceName = String.valueOf(input);
108            }
109            return Boolean.valueOf(m_cms.getRequestContext().getUri().startsWith(resourceName));
110        }
111    }
112
113    /** The navigation builder. */
114    protected CmsJspNavBuilder m_builder;
115
116    /** The OpenCms user context. */
117    protected CmsObject m_cms;
118
119    /** The navigation element of the currently requested uri. */
120    protected CmsJspNavElement m_current;
121
122    /** The optional end level for the navigation. */
123    protected int m_endLevel;
124
125    /** Indicates if a given navigation uri is currently active. */
126    protected Map<String, Boolean> m_isActive;
127
128    /** Indicates if the given navigation URI is a parent element of the current URI. */
129    protected Map<String, Boolean> m_isParent;
130
131    /** The result items from the navigation. */
132    protected List<CmsJspNavElement> m_items;
133
134    /** The optional parameter for the navigation. */
135    protected String m_param;
136
137    /** The optional resource for the navigation. */
138    protected String m_resource;
139
140    /** The optional start level for the navigation. */
141    protected int m_startLevel;
142
143    /** The selected navigation type. */
144    protected CmsJspTagNavigation.Type m_type;
145
146    /**
147     * Base constructor.<p>
148     *
149     * @param cms the current users OpenCms context to build the navigation for
150     * @param type the navigation type to generate
151     * @param startLevel the optional start level
152     * @param endLevel the optional end level
153     * @param resource the optional resource for the navigation
154     * @param param the optional parameter for the navigation
155     */
156    public CmsJspNavigationBean(
157        CmsObject cms,
158        CmsJspTagNavigation.Type type,
159        int startLevel,
160        int endLevel,
161        String resource,
162        String param) {
163        this(cms, type, startLevel, endLevel, resource, param, null);
164    }
165
166    /**
167     * Base constructor.<p>
168     *
169     * @param cms the current users OpenCms context to build the navigation for
170     * @param type the navigation type to generate
171     * @param startLevel the optional start level
172     * @param endLevel the optional end level
173     * @param resource the optional resource for the navigation
174     * @param param the optional parameter for the navigation
175     * @param locale the locale, for which Properties should be read.
176     */
177    public CmsJspNavigationBean(
178        CmsObject cms,
179        CmsJspTagNavigation.Type type,
180        int startLevel,
181        int endLevel,
182        String resource,
183        String param,
184        Locale locale) {
185
186        m_cms = cms;
187        m_builder = new CmsJspNavBuilder(m_cms, locale);
188        m_type = type;
189        m_startLevel = startLevel;
190        m_endLevel = endLevel;
191        m_resource = resource;
192        m_param = param;
193    }
194
195    /**
196     * Returns the navigation element of the currently requested uri.<p>
197     *
198     * @return the navigation element of the currently requested uri
199     */
200    public CmsJspNavElement getCurrent() {
201
202        if (m_current == null) {
203            m_current = m_builder.getNavigationForResource();
204        }
205        return m_current;
206    }
207
208    /**
209     * Returns a lazy initialized Map that provides Booleans that
210     * indicate if a given navigation uri is currently active.<p>
211     *
212     * The provided Map key is assumed to be a String that represents an absolute VFS path.<p>
213     *
214     * Usage example on a JSP with the JSTL:<pre>
215     * &lt;cms:navigation  type="treeForFolder" startLevel="1" endLevel="3" var="nav" /&gt;
216     *     &lt;c:forEach var="entry" items="${nav.items}" ... &gt;
217     *     ...
218     *     &lt;c:if test="${nav.isActive[entry.resourceName]}" &gt;
219     *         This is the currently active navigation entry
220     *     &lt;/c:if&gt;
221     * &lt;/c:forEach&gt;</pre>
222     *
223     * @return a lazy initialized Map that provides Booleans that
224     *      indicate if a given navigation uri is currently active
225     */
226    public Map<String, Boolean> getIsActive() {
227
228        if (m_isActive == null) {
229            m_isActive = CmsCollectionsGenericWrapper.createLazyMap(new CmsIsActiveTransformer());
230        }
231        return m_isActive;
232    }
233
234    /**
235     * Returns a lazy initialized Map that provides Booleans that
236     * indicate if the given navigation URI is a parent element of the current URI.<p>
237     *
238     * The provided Map key is assumed to be a String that represents an absolute VFS path.<p>
239     *
240     * Usage example on a JSP with the JSTL:<pre>
241     * &lt;cms:navigation  type="treeForFolder" startLevel="1" endLevel="3" var="nav" /&gt;
242     *     &lt;c:forEach var="entry" items="${nav.items}" ... &gt;
243     *     ...
244     *     &lt;c:if test="${nav.isParent[entry.resourceName]}" &gt;
245     *         The currently active navigation entry is a parent of the currently requested URI
246     *     &lt;/c:if&gt;
247     * &lt;/c:forEach&gt;</pre>
248     *
249     * @return a lazy initialized Map that provides Booleans that
250     *      indicate if the given navigation URI is a parent element of the current URI
251     */
252    public Map<String, Boolean> getIsParent() {
253
254        if (m_isParent == null) {
255            m_isParent = CmsCollectionsGenericWrapper.createLazyMap(new CmsIsParentTransformer());
256        }
257        return m_isParent;
258    }
259
260    /**
261     * Returns the list of selected navigation elements.<p>
262     *
263     * @return the list of selected navigation elements
264     */
265    public List<CmsJspNavElement> getItems() {
266
267        if (m_items == null) {
268            switch (m_type) {
269                // calculate the results based on the given parameters
270                case forFolder:
271                    if (m_startLevel == Integer.MIN_VALUE) {
272                        // no start level set
273                        if (m_resource == null) {
274                            m_items = m_builder.getNavigationForFolder();
275                        } else {
276                            m_items = m_builder.getNavigationForFolder(m_resource);
277                        }
278                    } else {
279                        // start level is set
280                        if (m_resource == null) {
281                            m_items = m_builder.getNavigationForFolder(m_startLevel);
282                        } else {
283                            m_items = m_builder.getNavigationForFolder(m_resource, m_startLevel);
284                        }
285                    }
286                    break;
287                case forSite:
288                    if (m_resource == null) {
289                        m_items = m_builder.getSiteNavigation();
290                    } else {
291                        m_items = m_builder.getSiteNavigation(m_resource, m_endLevel);
292                    }
293                    break;
294                case breadCrumb:
295                    if (m_resource != null) {
296                        // resource is set
297                        m_items = m_builder.getNavigationBreadCrumb(
298                            m_resource,
299                            m_startLevel,
300                            m_endLevel,
301                            Boolean.valueOf(m_param).booleanValue());
302                    } else {
303                        if (m_startLevel == Integer.MIN_VALUE) {
304                            // default start level is zero
305                            m_items = m_builder.getNavigationBreadCrumb(0, Boolean.valueOf(m_param).booleanValue());
306                        } else {
307                            if (m_endLevel != Integer.MIN_VALUE) {
308                                m_items = m_builder.getNavigationBreadCrumb(m_startLevel, m_endLevel);
309                            } else {
310                                m_items = m_builder.getNavigationBreadCrumb(
311                                    m_startLevel,
312                                    Boolean.valueOf(m_param).booleanValue());
313                            }
314                        }
315                    }
316                    break;
317                case treeForFolder:
318                    if (m_resource == null) {
319                        m_items = m_builder.getNavigationTreeForFolder(m_startLevel, m_endLevel);
320                    } else {
321                        m_items = m_builder.getNavigationTreeForFolder(m_resource, m_startLevel, m_endLevel);
322                    }
323                    break;
324                case forResource:
325                default:
326                    List<CmsJspNavElement> items = new ArrayList<CmsJspNavElement>(1);
327                    if (m_resource == null) {
328                        items.add(m_builder.getNavigationForResource());
329                    } else {
330                        items.add(m_builder.getNavigationForResource(m_resource));
331                    }
332                    m_items = items;
333                    break;
334            }
335        }
336        return m_items;
337    }
338}