001    /**
002     * Copyright (c) 2000-present 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.language.LanguageUtil;
019    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
020    import com.liferay.portal.kernel.util.DateUtil;
021    import com.liferay.portal.kernel.util.LocaleUtil;
022    import com.liferay.portal.kernel.util.StringPool;
023    import com.liferay.portal.kernel.util.StringUtil;
024    import com.liferay.portal.kernel.util.UnicodeProperties;
025    import com.liferay.portal.kernel.util.Validator;
026    import com.liferay.portal.kernel.xml.Document;
027    import com.liferay.portal.kernel.xml.Element;
028    import com.liferay.portal.kernel.xml.SAXReaderUtil;
029    import com.liferay.portal.model.Layout;
030    import com.liferay.portal.model.LayoutConstants;
031    import com.liferay.portal.service.LayoutLocalServiceUtil;
032    import com.liferay.portal.theme.ThemeDisplay;
033    import com.liferay.portal.util.PortalUtil;
034    import com.liferay.portal.util.PropsValues;
035    
036    import java.text.DateFormat;
037    
038    import java.util.Date;
039    import java.util.HashMap;
040    import java.util.List;
041    import java.util.Locale;
042    import java.util.Map;
043    
044    /**
045     * @author Jorge Ferrer
046     * @author Vilmos Papp
047     */
048    @DoPrivileged
049    public class SitemapImpl implements Sitemap {
050    
051            @Override
052            public void addURLElement(
053                    Element element, String url, UnicodeProperties typeSettingsProperties,
054                    Date modifiedDate, String canonicalURL,
055                    Map<Locale, String> alternateURLs) {
056    
057                    Element urlElement = element.addElement("url");
058    
059                    Element locElement = urlElement.addElement("loc");
060    
061                    locElement.addText(encodeXML(url));
062    
063                    if (typeSettingsProperties == null) {
064                            if (Validator.isNotNull(
065                                            PropsValues.SITES_SITEMAP_DEFAULT_CHANGE_FREQUENCY)) {
066    
067                                    Element changefreqElement = urlElement.addElement("changefreq");
068    
069                                    changefreqElement.addText(
070                                            PropsValues.SITES_SITEMAP_DEFAULT_CHANGE_FREQUENCY);
071                            }
072    
073                            if (Validator.isNotNull(
074                                            PropsValues.SITES_SITEMAP_DEFAULT_PRIORITY)) {
075    
076                                    Element priorityElement = urlElement.addElement("priority");
077    
078                                    priorityElement.addText(
079                                            PropsValues.SITES_SITEMAP_DEFAULT_PRIORITY);
080                            }
081                    }
082                    else {
083                            String changefreq = typeSettingsProperties.getProperty(
084                                    "sitemap-changefreq");
085    
086                            if (Validator.isNotNull(changefreq)) {
087                                    Element changefreqElement = urlElement.addElement("changefreq");
088    
089                                    changefreqElement.addText(changefreq);
090                            }
091                            else if (Validator.isNotNull(
092                                                    PropsValues.SITES_SITEMAP_DEFAULT_CHANGE_FREQUENCY)) {
093    
094                                    Element changefreqElement = urlElement.addElement("changefreq");
095    
096                                    changefreqElement.addText(
097                                            PropsValues.SITES_SITEMAP_DEFAULT_CHANGE_FREQUENCY);
098                            }
099    
100                            String priority = typeSettingsProperties.getProperty(
101                                    "sitemap-priority");
102    
103                            if (Validator.isNotNull(priority)) {
104                                    Element priorityElement = urlElement.addElement("priority");
105    
106                                    priorityElement.addText(priority);
107                            }
108                            else if (Validator.isNotNull(
109                                                    PropsValues.SITES_SITEMAP_DEFAULT_PRIORITY)) {
110    
111                                    Element priorityElement = urlElement.addElement("priority");
112    
113                                    priorityElement.addText(
114                                            PropsValues.SITES_SITEMAP_DEFAULT_PRIORITY);
115                            }
116                    }
117    
118                    if (modifiedDate != null) {
119                            Element modifiedDateElement = urlElement.addElement("lastmod");
120    
121                            DateFormat iso8601DateFormat = DateUtil.getISO8601Format();
122    
123                            modifiedDateElement.addText(iso8601DateFormat.format(modifiedDate));
124                    }
125    
126                    if (alternateURLs != null) {
127                            for (Map.Entry<Locale, String> entry : alternateURLs.entrySet()) {
128                                    Locale locale = entry.getKey();
129                                    String href = entry.getValue();
130    
131                                    Element alternateURLElement = urlElement.addElement(
132                                            "xhtml:link", "http://www.w3.org/1999/xhtml");
133    
134                                    alternateURLElement.addAttribute("href", href);
135                                    alternateURLElement.addAttribute(
136                                            "hreflang", LocaleUtil.toW3cLanguageId(locale));
137                                    alternateURLElement.addAttribute("rel", "alternate");
138                            }
139    
140                            Element alternateURLElement = urlElement.addElement(
141                                    "xhtml:link", "http://www.w3.org/1999/xhtml");
142    
143                            alternateURLElement.addAttribute("rel", "alternate");
144                            alternateURLElement.addAttribute("hreflang", "x-default");
145                            alternateURLElement.addAttribute("href", canonicalURL);
146                    }
147            }
148    
149            @Override
150            public String encodeXML(String input) {
151                    return StringUtil.replace(
152                            input,
153                            new String[] {"&", "<", ">", "'", "\""},
154                            new String[] {"&amp;", "&lt;", "&gt;", "&apos;", "&quot;"});
155            }
156    
157            @Override
158            public Map<Locale, String> getAlternateURLs(
159                            String canonicalURL, ThemeDisplay themeDisplay, Layout layout)
160                    throws PortalException {
161    
162                    Map<Locale, String> alternateURLs = new HashMap<>();
163    
164                    for (Locale availableLocale : LanguageUtil.getAvailableLocales(
165                                    layout.getGroupId())) {
166    
167                            String alternateURL = PortalUtil.getAlternateURL(
168                                    canonicalURL, themeDisplay, availableLocale, layout);
169    
170                            alternateURLs.put(availableLocale, alternateURL);
171                    }
172    
173                    return alternateURLs;
174            }
175    
176            @Override
177            public String getSitemap(
178                            long groupId, boolean privateLayout, ThemeDisplay themeDisplay)
179                    throws PortalException {
180    
181                    Document document = SAXReaderUtil.createDocument();
182    
183                    document.setXMLEncoding(StringPool.UTF8);
184    
185                    Element rootElement = document.addElement(
186                            "urlset", "http://www.sitemaps.org/schemas/sitemap/0.9");
187    
188                    rootElement.addAttribute("xmlns:xhtml", "http://www.w3.org/1999/xhtml");
189    
190                    List<Layout> layouts = LayoutLocalServiceUtil.getLayouts(
191                            groupId, privateLayout, LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);
192    
193                    List<SitemapURLProvider> sitemapURLProviders =
194                            SitemapURLProviderRegistryUtil.getSitemapURLProviders();
195    
196                    visitLayouts(rootElement, layouts, sitemapURLProviders, themeDisplay);
197    
198                    return document.asXML();
199            }
200    
201            protected void visitLayouts(
202                            Element element, List<Layout> layouts,
203                            List<SitemapURLProvider> sitemapURLProviders,
204                            ThemeDisplay themeDisplay)
205                    throws PortalException {
206    
207                    for (Layout layout : layouts) {
208                            for (SitemapURLProvider sitemapURLProvider : sitemapURLProviders) {
209                                    sitemapURLProvider.visitLayout(element, layout, themeDisplay);
210                            }
211    
212                            visitLayouts(
213                                    element, layout.getChildren(), sitemapURLProviders,
214                                    themeDisplay);
215                    }
216            }
217    
218    }