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.LayoutLocalServiceUtil;
035 import com.liferay.portal.service.LayoutSetLocalServiceUtil;
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 LayoutSetLocalServiceUtil.getLayoutSet(
233 journalArticle.getGroupId(), false),
234 themeDisplay);
235
236 StringBundler sb = new StringBundler(4);
237
238 if (!groupFriendlyURL.startsWith(portalURL)) {
239 sb.append(portalURL);
240 }
241
242 sb.append(groupFriendlyURL);
243 sb.append(JournalArticleConstants.CANONICAL_URL_SEPARATOR);
244 sb.append(journalArticle.getUrlTitle());
245
246 String articleURL = PortalUtil.getCanonicalURL(
247 sb.toString(), themeDisplay, layout);
248
249 addURLElement(
250 element, articleURL, null, journalArticle.getModifiedDate(),
251 articleURL, getAlternateURLs(articleURL, themeDisplay, layout));
252
253 Locale[] availableLocales = LanguageUtil.getAvailableLocales(
254 layout.getGroupId());
255
256 if (availableLocales.length > 1) {
257 Locale defaultLocale = LocaleUtil.getSiteDefault();
258
259 for (Locale availableLocale : availableLocales) {
260 if (!availableLocale.equals(defaultLocale)) {
261 String alternateURL = PortalUtil.getAlternateURL(
262 articleURL, themeDisplay, availableLocale, layout);
263
264 addURLElement(
265 element, alternateURL, null,
266 journalArticle.getModifiedDate(), articleURL,
267 getAlternateURLs(articleURL, themeDisplay, layout));
268 }
269 }
270 }
271
272 processedArticleIds.add(journalArticle.getArticleId());
273 }
274 }
275
276 protected void visitLayout(
277 Element element, Layout layout, ThemeDisplay themeDisplay)
278 throws PortalException {
279
280 UnicodeProperties typeSettingsProperties =
281 layout.getTypeSettingsProperties();
282
283 if (!PortalUtil.isLayoutSitemapable(layout) ||
284 !GetterUtil.getBoolean(
285 typeSettingsProperties.getProperty("sitemap-include"), true)) {
286
287 return;
288 }
289
290 String layoutFullURL = PortalUtil.getLayoutFullURL(
291 layout, themeDisplay);
292
293 layoutFullURL = PortalUtil.getCanonicalURL(
294 layoutFullURL, themeDisplay, layout);
295
296 addURLElement(
297 element, layoutFullURL, typeSettingsProperties,
298 layout.getModifiedDate(), layoutFullURL,
299 getAlternateURLs(layoutFullURL, themeDisplay, layout));
300
301 Locale[] availableLocales = LanguageUtil.getAvailableLocales(
302 layout.getGroupId());
303
304 if (availableLocales.length > 1) {
305 Locale defaultLocale = LocaleUtil.getSiteDefault();
306
307 for (Locale availableLocale : availableLocales) {
308 if (availableLocale.equals(defaultLocale)) {
309 continue;
310 }
311
312 String alternateURL = PortalUtil.getAlternateURL(
313 layoutFullURL, themeDisplay, availableLocale, layout);
314
315 addURLElement(
316 element, alternateURL, typeSettingsProperties,
317 layout.getModifiedDate(), layoutFullURL,
318 getAlternateURLs(layoutFullURL, themeDisplay, layout));
319 }
320 }
321 }
322
323 protected void visitLayouts(
324 Element element, List<Layout> layouts, ThemeDisplay themeDisplay)
325 throws PortalException {
326
327 for (Layout layout : layouts) {
328 visitLayout(element, layout, themeDisplay);
329
330 visitArticles(element, layout, themeDisplay);
331
332 visitLayouts(element, layout.getChildren(), themeDisplay);
333 }
334 }
335
336 }