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