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.ade.containerpage.CmsDetailOnlyContainerUtil;
031import org.opencms.file.CmsObject;
032import org.opencms.file.CmsResource;
033import org.opencms.file.CmsResourceFilter;
034import org.opencms.main.CmsException;
035import org.opencms.main.CmsLog;
036import org.opencms.main.OpenCms;
037import org.opencms.util.CmsCollectionsGenericWrapper;
038import org.opencms.util.CmsFileUtil;
039import org.opencms.xml.containerpage.CmsContainerBean;
040import org.opencms.xml.containerpage.CmsContainerElementBean;
041import org.opencms.xml.containerpage.CmsContainerPageBean;
042import org.opencms.xml.containerpage.CmsXmlContainerPage;
043import org.opencms.xml.containerpage.CmsXmlContainerPageFactory;
044
045import java.util.ArrayList;
046import java.util.Collections;
047import java.util.List;
048import java.util.Locale;
049import java.util.Map;
050import java.util.Set;
051
052import org.apache.commons.collections.Transformer;
053import org.apache.commons.logging.Log;
054
055import com.google.common.base.Optional;
056import com.google.common.collect.Lists;
057import com.google.common.collect.Sets;
058
059/**
060 * Allows accessing 'attachments' of an XML content via the EL in JSP code, which in OpenCms are defined as the contents of its detail-only containers.
061 */
062public class CmsJspContentAttachmentsBean {
063
064    /** The logger instance for this class. */
065    private static final Log LOG = CmsLog.getLog(CmsJspContentAttachmentsBean.class);
066
067    /** The container page bean. */
068    protected CmsContainerPageBean m_page;
069
070    /** Lazy map from container names to lists of elements. */
071    private Map<?, ?> m_byContainer;
072
073    /** Lazy map from type names to lists of elements. */
074    private Map<?, ?> m_byType;
075
076    /** Flag which indicates whether this is an empty attachments bean. */
077    private boolean m_undefined;
078
079    /** The CmsObject to read the detail page and the resources on that page. */
080    private CmsObject m_cms;
081
082    /**
083     * Creates an 'undefined' attachments bean.<p>
084     */
085    public CmsJspContentAttachmentsBean() {
086        m_page = new CmsContainerPageBean(new ArrayList<CmsContainerBean>());
087        m_undefined = true;
088
089    }
090
091    /**
092     * Initializes this bean with the contents of a detail-only page.<p>
093     *
094     * @param cms the CMS context
095     * @param pageResource the detail-only container page
096     *
097     * @throws CmsException if something goes wrong
098     */
099    public CmsJspContentAttachmentsBean(CmsObject cms, CmsResource pageResource)
100    throws CmsException {
101
102        CmsXmlContainerPage xmlContainerPage = CmsXmlContainerPageFactory.unmarshal(cms, pageResource);
103        m_page = xmlContainerPage.getContainerPage(cms);
104        m_cms = cms;
105
106    }
107
108    /**
109     * Gets the list of locales for which attachments / detail-only containers are available.<p>
110     *
111     * @param cms the current CMS context
112     * @param content the content resource
113     *
114     * @return the list of locales for which there are attachments
115     */
116    public static List<String> getAttachmentLocales(CmsObject cms, CmsResource content) {
117
118        List<CmsResource> detailOnlyResources = CmsDetailOnlyContainerUtil.getDetailOnlyResources(cms, content);
119        Set<String> validLocaleNames = Sets.newHashSet();
120        List<String> result = Lists.newArrayList();
121        for (Locale locale : OpenCms.getLocaleManager().getAvailableLocales()) {
122            validLocaleNames.add(locale.toString());
123        }
124        validLocaleNames.add(CmsDetailOnlyContainerUtil.LOCALE_ALL);
125        for (CmsResource resource : detailOnlyResources) {
126            String parent = CmsResource.getParentFolder(resource.getRootPath());
127            String parentName = CmsResource.getName(parent);
128            parentName = CmsFileUtil.removeTrailingSeparator(parentName);
129            if (validLocaleNames.contains(parentName)) {
130                result.add(parentName);
131            }
132        }
133        return result;
134
135    }
136
137    /**
138     * Gets the attachments / detail-only contents for the current page (i.e. cms.getRequestContext().getUri()).<p>
139     *
140     * @param cms the CMS context
141     * @param content the content for which to get the attachments
142     * @return a bean providing access to the attachments for the resource
143     *
144     * @throws CmsException if something goes wrong
145     */
146    public static CmsJspContentAttachmentsBean getAttachmentsForCurrentPage(CmsObject cms, CmsResource content)
147    throws CmsException {
148
149        CmsResource page = cms.readResource(cms.getRequestContext().getUri(), CmsResourceFilter.IGNORE_EXPIRATION);
150        String locale = CmsDetailOnlyContainerUtil.getDetailContainerLocale(
151            cms,
152            cms.getRequestContext().getLocale().toString(),
153            page);
154        Optional<CmsResource> detailOnly = CmsDetailOnlyContainerUtil.getDetailOnlyPage(cms, content, locale);
155        if (detailOnly.isPresent()) {
156            try {
157                return new CmsJspContentAttachmentsBean(cms, detailOnly.get());
158            } catch (Exception e) {
159                LOG.error(e.getLocalizedMessage(), e);
160                return new CmsJspContentAttachmentsBean();
161            }
162        } else {
163            return new CmsJspContentAttachmentsBean();
164        }
165    }
166
167    /**
168     * Loads the attachments for a given content.<p>
169     *
170     * @param cms the CMS context
171     * @param content the content
172     * @param locale the locale
173     *
174     * @return the attachment bean for the given content and locale
175     */
176    public static CmsJspContentAttachmentsBean getAttachmentsForLocale(
177        CmsObject cms,
178        CmsResource content,
179        String locale) {
180
181        Optional<CmsResource> detailOnly = CmsDetailOnlyContainerUtil.getDetailOnlyPage(cms, content, locale);
182        if (!detailOnly.isPresent()) {
183            return new CmsJspContentAttachmentsBean();
184        } else {
185            try {
186                return new CmsJspContentAttachmentsBean(cms, detailOnly.get());
187            } catch (Exception e) {
188                LOG.error(e.getLocalizedMessage(), e);
189                return new CmsJspContentAttachmentsBean();
190            }
191        }
192    }
193
194    /**
195     * Gets lazy map that returns lists of element beans for the container whose name is given as a key.<p>
196     *
197     * @return a lazy map to fetch contents of a container
198     */
199    public Map<?, ?> getByContainer() {
200
201        if (m_byContainer == null) {
202            m_byContainer = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() {
203
204                public Object transform(Object arg0) {
205
206                    String key = (String)arg0;
207                    CmsContainerBean container = m_page.getContainers().get(key);
208                    if (container == null) {
209                        return Collections.emptyList();
210                    } else {
211                        return container.getElements();
212                    }
213                }
214            });
215        }
216        return m_byContainer;
217    }
218
219    /**
220     * Gets lazy map that maps type names to lists of container elements of that type.<p>
221     *
222     * @return a map from type names to lists of container elements
223     */
224    public Map<?, ?> getByType() {
225
226        if (m_byType == null) {
227            m_byType = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() {
228
229                @SuppressWarnings("synthetic-access")
230                public Object transform(Object arg0) {
231
232                    String key = (String)arg0;
233                    List<CmsContainerElementBean> result = Lists.newArrayList();
234                    for (Map.Entry<String, CmsContainerBean> entry : getPage().getContainers().entrySet()) {
235                        CmsContainerBean value = entry.getValue();
236                        for (CmsContainerElementBean element : value.getElements()) {
237                            try {
238                                element.initResource(m_cms);
239                                if (key.equals(element.getTypeName())) {
240                                    result.add(element);
241                                }
242                            } catch (CmsException e) {
243                                LOG.error(
244                                    "Could not initialize resource with site path \""
245                                        + element.getSitePath()
246                                        + "\" to determine the container elements type.",
247                                    e);
248                            }
249                        }
250                    }
251                    return result;
252                }
253            });
254        }
255        return m_byType;
256    }
257
258    /**
259     * Gets the set of container names.<p>
260     *
261     * @return the set of container names
262     */
263    public Set<String> getContainers() {
264
265        return Sets.newHashSet(m_page.getContainers().keySet());
266    }
267
268    /**
269     * Returns true if the attachments are undefined.<p>
270     *
271     * @return true if the attachments are undefined
272     */
273    public boolean isUndefined() {
274
275        return m_undefined;
276    }
277
278    /**
279     * Gets the container page bean for the detail-only page.<p>
280     *
281     * @return the container page bean
282     */
283    protected CmsContainerPageBean getPage() {
284
285        return m_page;
286    }
287
288}