001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portlet.layoutsadmin.util;
016    
017    import com.liferay.portal.kernel.exception.PortalException;
018    import com.liferay.portal.kernel.exception.SystemException;
019    import com.liferay.portal.kernel.language.LanguageUtil;
020    import com.liferay.portal.kernel.util.DateUtil;
021    import com.liferay.portal.kernel.util.GetterUtil;
022    import com.liferay.portal.kernel.util.LocaleUtil;
023    import com.liferay.portal.kernel.util.StringBundler;
024    import com.liferay.portal.kernel.util.StringPool;
025    import com.liferay.portal.kernel.util.StringUtil;
026    import com.liferay.portal.kernel.util.UnicodeProperties;
027    import com.liferay.portal.kernel.util.Validator;
028    import com.liferay.portal.kernel.workflow.WorkflowConstants;
029    import com.liferay.portal.kernel.xml.Document;
030    import com.liferay.portal.kernel.xml.Element;
031    import com.liferay.portal.kernel.xml.SAXReaderUtil;
032    import com.liferay.portal.model.Layout;
033    import com.liferay.portal.model.LayoutConstants;
034    import com.liferay.portal.service.GroupLocalServiceUtil;
035    import com.liferay.portal.service.LayoutLocalServiceUtil;
036    import com.liferay.portal.theme.ThemeDisplay;
037    import com.liferay.portal.util.PortalUtil;
038    import com.liferay.portal.util.PropsValues;
039    import com.liferay.portlet.journal.model.JournalArticle;
040    import com.liferay.portlet.journal.model.JournalArticleConstants;
041    import com.liferay.portlet.journal.service.JournalArticleServiceUtil;
042    
043    import java.text.DateFormat;
044    
045    import java.util.Date;
046    import java.util.HashSet;
047    import java.util.List;
048    import java.util.Locale;
049    import java.util.Set;
050    
051    /**
052     * @author Jorge Ferrer
053     * @author Vilmos Papp
054     */
055    public class SitemapImpl implements Sitemap {
056    
057            public String encodeXML(String input) {
058                    return StringUtil.replace(
059                            input,
060                            new String[] {"&", "<", ">", "'", "\""},
061                            new String[] {"&amp;", "&lt;", "&gt;", "&apos;", "&quot;"});
062            }
063    
064            public String getSitemap(
065                            long groupId, boolean privateLayout, ThemeDisplay themeDisplay)
066                    throws PortalException, SystemException {
067    
068                    Document document = SAXReaderUtil.createDocument();
069    
070                    document.setXMLEncoding(StringPool.UTF8);
071    
072                    Element rootElement = document.addElement(
073                            "urlset", "http://www.google.com/schemas/sitemap/0.84");
074    
075                    List<Layout> layouts = LayoutLocalServiceUtil.getLayouts(
076                            groupId, privateLayout, LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);
077    
078                    visitLayouts(rootElement, layouts, themeDisplay);
079    
080                    return document.asXML();
081            }
082    
083            protected void addURLElement(
084                    Element element, String url, UnicodeProperties typeSettingsProperties,
085                    Date modifiedDate) {
086    
087                    Element urlElement = element.addElement("url");
088    
089                    Element locElement = urlElement.addElement("loc");
090    
091                    locElement.addText(encodeXML(url));
092    
093                    if (typeSettingsProperties == null) {
094                            if (Validator.isNotNull(
095                                            PropsValues.SITES_SITEMAP_DEFAULT_CHANGE_FREQUENCY)) {
096    
097                                    Element changefreqElement = urlElement.addElement("changefreq");
098    
099                                    changefreqElement.addText(
100                                            PropsValues.SITES_SITEMAP_DEFAULT_CHANGE_FREQUENCY);
101                            }
102    
103                            if (Validator.isNotNull(
104                                            PropsValues.SITES_SITEMAP_DEFAULT_PRIORITY)) {
105    
106                                    Element priorityElement = urlElement.addElement("priority");
107    
108                                    priorityElement.addText(
109                                            PropsValues.SITES_SITEMAP_DEFAULT_PRIORITY);
110                            }
111                    }
112                    else {
113                            String changefreq = typeSettingsProperties.getProperty(
114                                    "sitemap-changefreq");
115    
116                            if (Validator.isNotNull(changefreq)) {
117                                    Element changefreqElement = urlElement.addElement("changefreq");
118    
119                                    changefreqElement.addText(changefreq);
120                            }
121                            else if (Validator.isNotNull(
122                                                    PropsValues.SITES_SITEMAP_DEFAULT_CHANGE_FREQUENCY)) {
123    
124                                    Element changefreqElement = urlElement.addElement("changefreq");
125    
126                                    changefreqElement.addText(
127                                            PropsValues.SITES_SITEMAP_DEFAULT_CHANGE_FREQUENCY);
128                            }
129    
130                            String priority = typeSettingsProperties.getProperty(
131                                    "sitemap-priority");
132    
133                            if (Validator.isNotNull(priority)) {
134                                    Element priorityElement = urlElement.addElement("priority");
135    
136                                    priorityElement.addText(priority);
137                            }
138                            else if (Validator.isNotNull(
139                                                    PropsValues.SITES_SITEMAP_DEFAULT_PRIORITY)) {
140    
141                                    Element priorityElement = urlElement.addElement("priority");
142    
143                                    priorityElement.addText(
144                                            PropsValues.SITES_SITEMAP_DEFAULT_PRIORITY);
145                            }
146                    }
147    
148                    if (modifiedDate != null) {
149                            Element modifiedDateElement = urlElement.addElement("lastmod");
150    
151                            DateFormat iso8601DateFormat = DateUtil.getISO8601Format();
152    
153                            modifiedDateElement.addText(iso8601DateFormat.format(modifiedDate));
154                    }
155            }
156    
157            protected void visitArticles(
158                            Element element, Layout layout, ThemeDisplay themeDisplay)
159                    throws PortalException, SystemException {
160    
161                    List<JournalArticle> journalArticles =
162                            JournalArticleServiceUtil.getArticlesByLayoutUuid(
163                                    layout.getGroupId(), layout.getUuid());
164    
165                    if (journalArticles.isEmpty()) {
166                            return;
167                    }
168    
169                    Set<String> processedArticleIds = new HashSet<String>();
170    
171                    for (JournalArticle journalArticle : journalArticles) {
172                            if (processedArticleIds.contains(
173                                            journalArticle.getArticleId()) ||
174                                    (journalArticle.getStatus() !=
175                                            WorkflowConstants.STATUS_APPROVED)) {
176    
177                                    continue;
178                            }
179    
180                            String portalURL = PortalUtil.getPortalURL(layout, themeDisplay);
181    
182                            String groupFriendlyURL = PortalUtil.getGroupFriendlyURL(
183                                    GroupLocalServiceUtil.getGroup(journalArticle.getGroupId()),
184                                    false, themeDisplay);
185    
186                            StringBundler sb = new StringBundler(4);
187    
188                            if (!groupFriendlyURL.startsWith(portalURL)) {
189                                    sb.append(portalURL);
190                            }
191    
192                            sb.append(groupFriendlyURL);
193                            sb.append(JournalArticleConstants.CANONICAL_URL_SEPARATOR);
194                            sb.append(journalArticle.getUrlTitle());
195    
196                            String articleURL = PortalUtil.getCanonicalURL(
197                                    sb.toString(), themeDisplay, layout);
198    
199                            addURLElement(
200                                    element, articleURL, null, journalArticle.getModifiedDate());
201    
202                            Locale[] availableLocales = LanguageUtil.getAvailableLocales();
203    
204                            if (availableLocales.length > 1) {
205                                    Locale defaultLocale = LocaleUtil.getDefault();
206    
207                                    for (Locale availableLocale : availableLocales) {
208                                            if (!availableLocale.equals(defaultLocale)) {
209                                                    String alternateURL = PortalUtil.getAlternateURL(
210                                                            articleURL, themeDisplay, availableLocale);
211    
212                                                    addURLElement(
213                                                            element, alternateURL, null,
214                                                            journalArticle.getModifiedDate());
215                                            }
216                                    }
217                            }
218    
219                            processedArticleIds.add(journalArticle.getArticleId());
220                    }
221            }
222    
223            protected void visitLayout(
224                            Element element, Layout layout, ThemeDisplay themeDisplay)
225                    throws PortalException, SystemException {
226    
227                    UnicodeProperties typeSettingsProperties =
228                            layout.getTypeSettingsProperties();
229    
230                    if (layout.isHidden() || !PortalUtil.isLayoutSitemapable(layout) ||
231                            !GetterUtil.getBoolean(
232                                    typeSettingsProperties.getProperty("sitemap-include"), true)) {
233    
234                            return;
235                    }
236    
237                    String layoutFullURL = PortalUtil.getLayoutFullURL(
238                            layout, themeDisplay);
239    
240                    layoutFullURL = PortalUtil.getCanonicalURL(
241                            layoutFullURL, themeDisplay, layout);
242    
243                    addURLElement(
244                            element, layoutFullURL, typeSettingsProperties,
245                            layout.getModifiedDate());
246    
247                    Locale[] availableLocales = LanguageUtil.getAvailableLocales();
248    
249                    if (availableLocales.length > 1) {
250                            Locale defaultLocale = LocaleUtil.getDefault();
251    
252                            for (Locale availableLocale : availableLocales) {
253                                    if (availableLocale.equals(defaultLocale)) {
254                                            continue;
255                                    }
256    
257                                    String alternateURL = PortalUtil.getAlternateURL(
258                                            layoutFullURL, themeDisplay, availableLocale);
259    
260                                    addURLElement(
261                                            element, alternateURL, typeSettingsProperties,
262                                            layout.getModifiedDate());
263                            }
264                    }
265    
266                    visitArticles(element, layout, themeDisplay);
267                    visitLayouts(element, layout.getChildren(), themeDisplay);
268            }
269    
270            protected void visitLayouts(
271                            Element element, List<Layout> layouts, ThemeDisplay themeDisplay)
272                    throws PortalException, SystemException {
273    
274                    for (Layout layout : layouts) {
275                            visitLayout(element, layout, themeDisplay);
276                    }
277            }
278    
279    }