001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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.ArrayList;
046    import java.util.Date;
047    import java.util.List;
048    import java.util.Locale;
049    
050    /**
051     * @author Jorge Ferrer
052     * @author Vilmos Papp
053     */
054    public class SitemapImpl implements Sitemap {
055    
056            public String encodeXML(String input) {
057                    return StringUtil.replace(
058                            input,
059                            new String[] {"&", "<", ">", "'", "\""},
060                            new String[] {"&amp;", "&lt;", "&gt;", "&apos;", "&quot;"});
061            }
062    
063            public String getSitemap(
064                            long groupId, boolean privateLayout, ThemeDisplay themeDisplay)
065                    throws PortalException, SystemException {
066    
067                    Document document = SAXReaderUtil.createDocument();
068    
069                    document.setXMLEncoding(StringPool.UTF8);
070    
071                    Element rootElement = document.addElement(
072                            "urlset", "http://www.google.com/schemas/sitemap/0.84");
073    
074                    List<Layout> layouts = LayoutLocalServiceUtil.getLayouts(
075                            groupId, privateLayout, LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);
076    
077                    visitLayouts(rootElement, layouts, themeDisplay);
078    
079                    return document.asXML();
080            }
081    
082            protected void addURLElement(
083                    Element element, String url, UnicodeProperties typeSettingsProperties,
084                    Date modifiedDate) {
085    
086                    Element urlElement = element.addElement("url");
087    
088                    Element locElement = urlElement.addElement("loc");
089    
090                    locElement.addText(encodeXML(url));
091    
092                    if (typeSettingsProperties == null) {
093                            if (Validator.isNotNull(
094                                            PropsValues.SITES_SITEMAP_DEFAULT_CHANGE_FREQUENCY)) {
095    
096                                    Element changefreqElement = urlElement.addElement("changefreq");
097    
098                                    changefreqElement.addText(
099                                            PropsValues.SITES_SITEMAP_DEFAULT_CHANGE_FREQUENCY);
100                            }
101    
102                            if (Validator.isNotNull(
103                                            PropsValues.SITES_SITEMAP_DEFAULT_PRIORITY)) {
104    
105                                    Element priorityElement = urlElement.addElement("priority");
106    
107                                    priorityElement.addText(
108                                            PropsValues.SITES_SITEMAP_DEFAULT_PRIORITY);
109                            }
110                    }
111                    else {
112                            String changefreq = typeSettingsProperties.getProperty(
113                                    "sitemap-changefreq");
114    
115                            if (Validator.isNotNull(changefreq)) {
116                                    Element changefreqElement = urlElement.addElement("changefreq");
117    
118                                    changefreqElement.addText(changefreq);
119                            }
120                            else if (Validator.isNotNull(
121                                                    PropsValues.SITES_SITEMAP_DEFAULT_CHANGE_FREQUENCY)) {
122    
123                                    Element changefreqElement = urlElement.addElement("changefreq");
124    
125                                    changefreqElement.addText(
126                                            PropsValues.SITES_SITEMAP_DEFAULT_CHANGE_FREQUENCY);
127                            }
128    
129                            String priority = typeSettingsProperties.getProperty(
130                                    "sitemap-priority");
131    
132                            if (Validator.isNotNull(priority)) {
133                                    Element priorityElement = urlElement.addElement("priority");
134    
135                                    priorityElement.addText(priority);
136                            }
137                            else if (Validator.isNotNull(
138                                                    PropsValues.SITES_SITEMAP_DEFAULT_PRIORITY)) {
139    
140                                    Element priorityElement = urlElement.addElement("priority");
141    
142                                    priorityElement.addText(
143                                            PropsValues.SITES_SITEMAP_DEFAULT_PRIORITY);
144                            }
145                    }
146    
147                    if (modifiedDate != null) {
148                            Element modifiedDateElement = urlElement.addElement("lastmod");
149    
150                            DateFormat iso8601DateFormat = DateUtil.getISO8601Format();
151    
152                            modifiedDateElement.addText(iso8601DateFormat.format(modifiedDate));
153                    }
154            }
155    
156            protected void visitArticles(
157                            Element element, Layout layout, ThemeDisplay themeDisplay)
158                    throws PortalException, SystemException {
159    
160                    List<JournalArticle> journalArticles =
161                            JournalArticleServiceUtil.getArticlesByLayoutUuid(
162                                    layout.getGroupId(), layout.getUuid());
163    
164                    if (journalArticles.isEmpty()) {
165                            return;
166                    }
167    
168                    List<String> processedArticleIds = new ArrayList<String>();
169    
170                    for (JournalArticle journalArticle : journalArticles) {
171                            if (processedArticleIds.contains(
172                                            journalArticle.getArticleId()) ||
173                                    (journalArticle.getStatus() !=
174                                            WorkflowConstants.STATUS_APPROVED)) {
175    
176                                    continue;
177                            }
178    
179                            String portalURL = PortalUtil.getPortalURL(layout, themeDisplay);
180    
181                            String groupFriendlyURL = PortalUtil.getGroupFriendlyURL(
182                                    GroupLocalServiceUtil.getGroup(journalArticle.getGroupId()),
183                                    false, themeDisplay);
184    
185                            StringBundler sb = new StringBundler(4);
186    
187                            if (!groupFriendlyURL.startsWith(portalURL)) {
188                                    sb.append(portalURL);
189                            }
190    
191                            sb.append(groupFriendlyURL);
192                            sb.append(JournalArticleConstants.CANONICAL_URL_SEPARATOR);
193                            sb.append(journalArticle.getUrlTitle());
194    
195                            String articleURL = PortalUtil.getCanonicalURL(
196                                    sb.toString(), themeDisplay, layout);
197    
198                            addURLElement(
199                                    element, articleURL, null, journalArticle.getModifiedDate());
200    
201                            Locale[] availableLocales = LanguageUtil.getAvailableLocales();
202    
203                            if (availableLocales.length > 1) {
204                                    Locale defaultLocale = LocaleUtil.getDefault();
205    
206                                    for (Locale availableLocale : availableLocales) {
207                                            if (!availableLocale.equals(defaultLocale)) {
208                                                    String alternateURL = PortalUtil.getAlternateURL(
209                                                            articleURL, themeDisplay, availableLocale);
210    
211                                                    addURLElement(
212                                                            element, alternateURL, null,
213                                                            journalArticle.getModifiedDate());
214                                            }
215                                    }
216                            }
217    
218                            processedArticleIds.add(journalArticle.getArticleId());
219                    }
220            }
221    
222            protected void visitLayout(
223                            Element element, Layout layout, ThemeDisplay themeDisplay)
224                    throws PortalException, SystemException {
225    
226                    UnicodeProperties typeSettingsProperties =
227                            layout.getTypeSettingsProperties();
228    
229                    if (layout.isHidden() || !PortalUtil.isLayoutSitemapable(layout) ||
230                            !GetterUtil.getBoolean(
231                                    typeSettingsProperties.getProperty("sitemap-include"), true)) {
232    
233                            return;
234                    }
235    
236                    String layoutFullURL = PortalUtil.getLayoutFullURL(
237                            layout, themeDisplay);
238    
239                    layoutFullURL = PortalUtil.getCanonicalURL(
240                            layoutFullURL, themeDisplay, layout);
241    
242                    addURLElement(
243                            element, layoutFullURL, typeSettingsProperties,
244                            layout.getModifiedDate());
245    
246                    Locale[] availableLocales = LanguageUtil.getAvailableLocales();
247    
248                    if (availableLocales.length > 1) {
249                            Locale defaultLocale = LocaleUtil.getDefault();
250    
251                            for (Locale availableLocale : availableLocales) {
252                                    if (availableLocale.equals(defaultLocale)) {
253                                            continue;
254                                    }
255    
256                                    String alternateURL = PortalUtil.getAlternateURL(
257                                            layoutFullURL, themeDisplay, availableLocale);
258    
259                                    addURLElement(
260                                            element, alternateURL, typeSettingsProperties,
261                                            layout.getModifiedDate());
262                            }
263                    }
264    
265                    visitArticles(element, layout, themeDisplay);
266                    visitLayouts(element, layout.getChildren(), themeDisplay);
267            }
268    
269            protected void visitLayouts(
270                            Element element, List<Layout> layouts, ThemeDisplay themeDisplay)
271                    throws PortalException, SystemException {
272    
273                    for (Layout layout : layouts) {
274                            visitLayout(element, layout, themeDisplay);
275                    }
276            }
277    
278    }