001
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.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.HashMap;
047 import java.util.HashSet;
048 import java.util.List;
049 import java.util.Locale;
050 import java.util.Map;
051 import java.util.Set;
052
053
057 @DoPrivileged
058 public class SitemapImpl implements Sitemap {
059
060 @Override
061 public String encodeXML(String input) {
062 return StringUtil.replace(
063 input,
064 new String[] {"&", "<", ">", "'", "\""},
065 new String[] {"&", "<", ">", "'", """});
066 }
067
068 @Override
069 public String getSitemap(
070 long groupId, boolean privateLayout, ThemeDisplay themeDisplay)
071 throws PortalException {
072
073 Document document = SAXReaderUtil.createDocument();
074
075 document.setXMLEncoding(StringPool.UTF8);
076
077 Element rootElement = document.addElement(
078 "urlset", "http:
079
080 rootElement.addAttribute("xmlns:xhtml", "http:
081
082 List<Layout> layouts = LayoutLocalServiceUtil.getLayouts(
083 groupId, privateLayout, LayoutConstants.DEFAULT_PARENT_LAYOUT_ID);
084
085 visitLayouts(rootElement, layouts, themeDisplay);
086
087 return document.asXML();
088 }
089
090 protected void addURLElement(
091 Element element, String url, UnicodeProperties typeSettingsProperties,
092 Date modifiedDate, String canonicalURL,
093 Map<Locale, String> alternateURLs) {
094
095 Element urlElement = element.addElement("url");
096
097 Element locElement = urlElement.addElement("loc");
098
099 locElement.addText(encodeXML(url));
100
101 if (typeSettingsProperties == null) {
102 if (Validator.isNotNull(
103 PropsValues.SITES_SITEMAP_DEFAULT_CHANGE_FREQUENCY)) {
104
105 Element changefreqElement = urlElement.addElement("changefreq");
106
107 changefreqElement.addText(
108 PropsValues.SITES_SITEMAP_DEFAULT_CHANGE_FREQUENCY);
109 }
110
111 if (Validator.isNotNull(
112 PropsValues.SITES_SITEMAP_DEFAULT_PRIORITY)) {
113
114 Element priorityElement = urlElement.addElement("priority");
115
116 priorityElement.addText(
117 PropsValues.SITES_SITEMAP_DEFAULT_PRIORITY);
118 }
119 }
120 else {
121 String changefreq = typeSettingsProperties.getProperty(
122 "sitemap-changefreq");
123
124 if (Validator.isNotNull(changefreq)) {
125 Element changefreqElement = urlElement.addElement("changefreq");
126
127 changefreqElement.addText(changefreq);
128 }
129 else if (Validator.isNotNull(
130 PropsValues.SITES_SITEMAP_DEFAULT_CHANGE_FREQUENCY)) {
131
132 Element changefreqElement = urlElement.addElement("changefreq");
133
134 changefreqElement.addText(
135 PropsValues.SITES_SITEMAP_DEFAULT_CHANGE_FREQUENCY);
136 }
137
138 String priority = typeSettingsProperties.getProperty(
139 "sitemap-priority");
140
141 if (Validator.isNotNull(priority)) {
142 Element priorityElement = urlElement.addElement("priority");
143
144 priorityElement.addText(priority);
145 }
146 else if (Validator.isNotNull(
147 PropsValues.SITES_SITEMAP_DEFAULT_PRIORITY)) {
148
149 Element priorityElement = urlElement.addElement("priority");
150
151 priorityElement.addText(
152 PropsValues.SITES_SITEMAP_DEFAULT_PRIORITY);
153 }
154 }
155
156 if (modifiedDate != null) {
157 Element modifiedDateElement = urlElement.addElement("lastmod");
158
159 DateFormat iso8601DateFormat = DateUtil.getISO8601Format();
160
161 modifiedDateElement.addText(iso8601DateFormat.format(modifiedDate));
162 }
163
164 if (alternateURLs != null) {
165 for (Map.Entry<Locale, String> entry : alternateURLs.entrySet()) {
166 Locale locale = entry.getKey();
167 String href = entry.getValue();
168
169 Element alternateURLElement = urlElement.addElement(
170 "xhtml:link", "http:
171
172 alternateURLElement.addAttribute("href", href);
173 alternateURLElement.addAttribute(
174 "hreflang", LocaleUtil.toW3cLanguageId(locale));
175 alternateURLElement.addAttribute("rel", "alternate");
176 }
177
178 Element alternateURLElement = urlElement.addElement(
179 "xhtml:link", "http:
180
181 alternateURLElement.addAttribute("rel", "alternate");
182 alternateURLElement.addAttribute("hreflang", "x-default");
183 alternateURLElement.addAttribute("href", canonicalURL);
184 }
185 }
186
187 protected Map<Locale, String> getAlternateURLs(
188 String canonicalURL, ThemeDisplay themeDisplay, Layout layout)
189 throws PortalException {
190
191 Map<Locale, String> alternateURLs = new HashMap<Locale, String>();
192
193 Locale[] availableLocales = LanguageUtil.getAvailableLocales(
194 layout.getGroupId());
195
196 for (Locale availableLocale : availableLocales) {
197 String alternateURL = PortalUtil.getAlternateURL(
198 canonicalURL, themeDisplay, availableLocale, layout);
199
200 alternateURLs.put(availableLocale, alternateURL);
201 }
202
203 return alternateURLs;
204 }
205
206 protected void visitArticles(
207 Element element, Layout layout, ThemeDisplay themeDisplay)
208 throws PortalException {
209
210 List<JournalArticle> journalArticles =
211 JournalArticleServiceUtil.getArticlesByLayoutUuid(
212 layout.getGroupId(), layout.getUuid());
213
214 if (journalArticles.isEmpty()) {
215 return;
216 }
217
218 Set<String> processedArticleIds = new HashSet<String>();
219
220 for (JournalArticle journalArticle : journalArticles) {
221 if (processedArticleIds.contains(
222 journalArticle.getArticleId()) ||
223 (journalArticle.getStatus() !=
224 WorkflowConstants.STATUS_APPROVED)) {
225
226 continue;
227 }
228
229 String portalURL = PortalUtil.getPortalURL(layout, themeDisplay);
230
231 String groupFriendlyURL = PortalUtil.getGroupFriendlyURL(
232 GroupLocalServiceUtil.getGroup(journalArticle.getGroupId()),
233 false, themeDisplay);
234
235 StringBundler sb = new StringBundler(4);
236
237 if (!groupFriendlyURL.startsWith(portalURL)) {
238 sb.append(portalURL);
239 }
240
241 sb.append(groupFriendlyURL);
242 sb.append(JournalArticleConstants.CANONICAL_URL_SEPARATOR);
243 sb.append(journalArticle.getUrlTitle());
244
245 String articleURL = PortalUtil.getCanonicalURL(
246 sb.toString(), themeDisplay, layout);
247
248 addURLElement(
249 element, articleURL, null, journalArticle.getModifiedDate(),
250 articleURL, getAlternateURLs(articleURL, themeDisplay, layout));
251
252 Locale[] availableLocales = LanguageUtil.getAvailableLocales(
253 layout.getGroupId());
254
255 if (availableLocales.length > 1) {
256 Locale defaultLocale = LocaleUtil.getSiteDefault();
257
258 for (Locale availableLocale : availableLocales) {
259 if (!availableLocale.equals(defaultLocale)) {
260 String alternateURL = PortalUtil.getAlternateURL(
261 articleURL, themeDisplay, availableLocale, layout);
262
263 addURLElement(
264 element, alternateURL, null,
265 journalArticle.getModifiedDate(), articleURL,
266 getAlternateURLs(articleURL, themeDisplay, layout));
267 }
268 }
269 }
270
271 processedArticleIds.add(journalArticle.getArticleId());
272 }
273 }
274
275 protected void visitLayout(
276 Element element, Layout layout, ThemeDisplay themeDisplay)
277 throws PortalException {
278
279 UnicodeProperties typeSettingsProperties =
280 layout.getTypeSettingsProperties();
281
282 if (!PortalUtil.isLayoutSitemapable(layout) ||
283 !GetterUtil.getBoolean(
284 typeSettingsProperties.getProperty("sitemap-include"), true)) {
285
286 return;
287 }
288
289 String layoutFullURL = PortalUtil.getLayoutFullURL(
290 layout, themeDisplay);
291
292 layoutFullURL = PortalUtil.getCanonicalURL(
293 layoutFullURL, themeDisplay, layout);
294
295 addURLElement(
296 element, layoutFullURL, typeSettingsProperties,
297 layout.getModifiedDate(), layoutFullURL,
298 getAlternateURLs(layoutFullURL, themeDisplay, layout));
299
300 Locale[] availableLocales = LanguageUtil.getAvailableLocales(
301 layout.getGroupId());
302
303 if (availableLocales.length > 1) {
304 Locale defaultLocale = LocaleUtil.getSiteDefault();
305
306 for (Locale availableLocale : availableLocales) {
307 if (availableLocale.equals(defaultLocale)) {
308 continue;
309 }
310
311 String alternateURL = PortalUtil.getAlternateURL(
312 layoutFullURL, themeDisplay, availableLocale, layout);
313
314 addURLElement(
315 element, alternateURL, typeSettingsProperties,
316 layout.getModifiedDate(), layoutFullURL,
317 getAlternateURLs(layoutFullURL, themeDisplay, layout));
318 }
319 }
320 }
321
322 protected void visitLayouts(
323 Element element, List<Layout> layouts, ThemeDisplay themeDisplay)
324 throws PortalException {
325
326 for (Layout layout : layouts) {
327 visitLayout(element, layout, themeDisplay);
328
329 visitArticles(element, layout, themeDisplay);
330
331 visitLayouts(element, layout.getChildren(), themeDisplay);
332 }
333 }
334
335 }