1
22
23 package com.liferay.portal.servlet.filters.layoutcache;
24
25 import com.liferay.portal.NoSuchLayoutException;
26 import com.liferay.portal.kernel.language.LanguageUtil;
27 import com.liferay.portal.kernel.log.Log;
28 import com.liferay.portal.kernel.log.LogFactoryUtil;
29 import com.liferay.portal.kernel.servlet.BrowserSnifferUtil;
30 import com.liferay.portal.kernel.util.GetterUtil;
31 import com.liferay.portal.kernel.util.HttpUtil;
32 import com.liferay.portal.kernel.util.JavaConstants;
33 import com.liferay.portal.kernel.util.ParamUtil;
34 import com.liferay.portal.kernel.util.StringPool;
35 import com.liferay.portal.kernel.util.StringUtil;
36 import com.liferay.portal.kernel.util.UnicodeProperties;
37 import com.liferay.portal.kernel.util.Validator;
38 import com.liferay.portal.model.Group;
39 import com.liferay.portal.model.Layout;
40 import com.liferay.portal.model.LayoutConstants;
41 import com.liferay.portal.model.Portlet;
42 import com.liferay.portal.model.PortletConstants;
43 import com.liferay.portal.service.GroupLocalServiceUtil;
44 import com.liferay.portal.service.LayoutLocalServiceUtil;
45 import com.liferay.portal.service.PortletLocalServiceUtil;
46 import com.liferay.portal.servlet.filters.BasePortalFilter;
47 import com.liferay.portal.struts.LastPath;
48 import com.liferay.portal.util.PortalInstances;
49 import com.liferay.portal.util.PortalUtil;
50 import com.liferay.portal.util.PropsValues;
51 import com.liferay.portal.util.WebKeys;
52 import com.liferay.util.servlet.filters.CacheResponse;
53 import com.liferay.util.servlet.filters.CacheResponseData;
54 import com.liferay.util.servlet.filters.CacheResponseUtil;
55
56 import java.io.IOException;
57
58 import javax.servlet.FilterChain;
59 import javax.servlet.FilterConfig;
60 import javax.servlet.ServletException;
61 import javax.servlet.http.HttpServletRequest;
62 import javax.servlet.http.HttpServletResponse;
63 import javax.servlet.http.HttpSession;
64
65
73 public class LayoutCacheFilter extends BasePortalFilter {
74
75 public static final String SKIP_FILTER =
76 LayoutCacheFilter.class + "SKIP_FILTER";
77
78 public void init(FilterConfig filterConfig) {
79 super.init(filterConfig);
80
81 _pattern = GetterUtil.getInteger(
82 filterConfig.getInitParameter("pattern"));
83
84 if ((_pattern != _PATTERN_FRIENDLY) &&
85 (_pattern != _PATTERN_LAYOUT) &&
86 (_pattern != _PATTERN_RESOURCE)) {
87
88 _log.error("Layout cache pattern is invalid");
89 }
90 }
91
92 protected String getBrowserType(HttpServletRequest request) {
93 if (BrowserSnifferUtil.isIe(request) &&
94 BrowserSnifferUtil.getMajorVersion(request) == 7.0) {
95
96 return _BROWSER_TYPE_IE_7;
97 }
98 else if (BrowserSnifferUtil.isIe(request)) {
99 return _BROWSER_TYPE_IE;
100 }
101 else {
102 return _BROWSER_TYPE_OTHER;
103 }
104 }
105
106 protected String getCacheKey(HttpServletRequest request) {
107 StringBuilder sb = new StringBuilder();
108
109
111 sb.append(HttpUtil.getProtocol(request));
112 sb.append("://");
113 sb.append(request.getServletPath());
114 sb.append(request.getPathInfo());
115 sb.append(StringPool.QUESTION);
116 sb.append(request.getQueryString());
117
118
120 sb.append(StringPool.POUND);
121
122 String languageId = (String)request.getAttribute(
123 WebKeys.I18N_LANGUAGE_ID);
124
125 if (Validator.isNull(languageId)) {
126 languageId = LanguageUtil.getLanguageId(request);
127 }
128
129 sb.append(languageId);
130
131
133 sb.append(StringPool.POUND);
134 sb.append(getBrowserType(request));
135
136
138 sb.append(StringPool.POUND);
139 sb.append(BrowserSnifferUtil.acceptsGzip(request));
140
141 return sb.toString().trim().toUpperCase();
142 }
143
144 protected long getPlid(
145 long companyId, String pathInfo, String servletPath, long defaultPlid) {
146
147 if (_pattern == _PATTERN_LAYOUT) {
148 return defaultPlid;
149 }
150
151 if (Validator.isNull(pathInfo) ||
152 !pathInfo.startsWith(StringPool.SLASH)) {
153
154 return 0;
155 }
156
157
159 String friendlyURL = null;
160
161 int pos = pathInfo.indexOf(StringPool.SLASH, 1);
162
163 if (pos != -1) {
164 friendlyURL = pathInfo.substring(0, pos);
165 }
166 else {
167 if (pathInfo.length() > 1) {
168 friendlyURL = pathInfo.substring(0, pathInfo.length());
169 }
170 }
171
172 if (Validator.isNull(friendlyURL)) {
173 return 0;
174 }
175
176 long groupId = 0;
177 boolean privateLayout = false;
178
179 try {
180 Group group = GroupLocalServiceUtil.getFriendlyURLGroup(
181 companyId, friendlyURL);
182
183 groupId = group.getGroupId();
184
185 if (servletPath.startsWith(
186 PropsValues.
187 LAYOUT_FRIENDLY_URL_PRIVATE_GROUP_SERVLET_MAPPING) ||
188 servletPath.startsWith(
189 PropsValues.
190 LAYOUT_FRIENDLY_URL_PRIVATE_USER_SERVLET_MAPPING)) {
191
192 privateLayout = true;
193 }
194 else if (servletPath.startsWith(
195 PropsValues.
196 LAYOUT_FRIENDLY_URL_PUBLIC_SERVLET_MAPPING)) {
197
198 privateLayout = false;
199 }
200 }
201 catch (NoSuchLayoutException nsle) {
202 if (_log.isWarnEnabled()) {
203 _log.warn(nsle);
204 }
205 }
206 catch (Exception e) {
207 if (_log.isWarnEnabled()) {
208 _log.error(e);
209 }
210
211 return 0;
212 }
213
214
216 friendlyURL = null;
217
218 if ((pos != -1) && ((pos + 1) != pathInfo.length())) {
219 friendlyURL = pathInfo.substring(pos, pathInfo.length());
220 }
221
222 if (Validator.isNull(friendlyURL)) {
223 return 0;
224 }
225
226
228 try {
229 Layout layout = LayoutLocalServiceUtil.getFriendlyURLLayout(
230 groupId, privateLayout, friendlyURL);
231
232 return layout.getPlid();
233 }
234 catch (NoSuchLayoutException nsle) {
235 _log.warn(nsle);
236
237 return 0;
238 }
239 catch (Exception e) {
240 _log.error(e);
241
242 return 0;
243 }
244 }
245
246 protected boolean isAlreadyFiltered(HttpServletRequest request) {
247 if (request.getAttribute(SKIP_FILTER) != null) {
248 return true;
249 }
250 else {
251 return false;
252 }
253 }
254
255 protected boolean isCacheable(long companyId, HttpServletRequest request) {
256 if (_pattern == _PATTERN_RESOURCE) {
257 return true;
258 }
259
260 try {
261 long plid = getPlid(
262 companyId, request.getPathInfo(), request.getServletPath(),
263 ParamUtil.getLong(request, "p_l_id"));
264
265 if (plid <= 0) {
266 return false;
267 }
268
269 Layout layout = LayoutLocalServiceUtil.getLayout(plid);
270
271 if (!layout.getType().equals(LayoutConstants.TYPE_PORTLET)) {
272 return false;
273 }
274
275 UnicodeProperties props = layout.getTypeSettingsProperties();
276
277 for (int i = 0; i < 10; i++) {
278 String columnId = "column-" + i;
279
280 String settings = props.getProperty(columnId, StringPool.BLANK);
281
282 String[] portlets = StringUtil.split(settings);
283
284 for (int j = 0; j < portlets.length; j++) {
285 String portletId = StringUtil.extractFirst(
286 portlets[j], PortletConstants.INSTANCE_SEPARATOR);
287
288 Portlet portlet = PortletLocalServiceUtil.getPortletById(
289 companyId, portletId);
290
291 if (!portlet.isLayoutCacheable()) {
292 return false;
293 }
294 }
295 }
296 }
297 catch (Exception e) {
298 return false;
299 }
300
301 return true;
302 }
303
304 protected boolean isInclude(HttpServletRequest request) {
305 String uri = (String)request.getAttribute(
306 JavaConstants.JAVAX_SERVLET_INCLUDE_REQUEST_URI);
307
308 if (uri == null) {
309 return false;
310 }
311 else {
312 return true;
313 }
314 }
315
316 protected boolean isLayout(HttpServletRequest request) {
317 if ((_pattern == _PATTERN_FRIENDLY) ||
318 (_pattern == _PATTERN_RESOURCE)) {
319
320 return true;
321 }
322 else {
323 String plid = ParamUtil.getString(request, "p_l_id");
324
325 if (Validator.isNotNull(plid)) {
326 return true;
327 }
328 else {
329 return false;
330 }
331 }
332 }
333
334 protected boolean isPortletRequest(HttpServletRequest request) {
335 String portletId = ParamUtil.getString(request, "p_p_id");
336
337 if (Validator.isNull(portletId)) {
338 return false;
339 }
340 else {
341 return true;
342 }
343 }
344
345 protected boolean isSignedIn(HttpServletRequest request) {
346 long userId = PortalUtil.getUserId(request);
347 String remoteUser = request.getRemoteUser();
348
349 if ((userId <= 0) && (remoteUser == null)) {
350 return false;
351 }
352 else {
353 return true;
354 }
355 }
356
357 protected void processFilter(
358 HttpServletRequest request, HttpServletResponse response,
359 FilterChain filterChain)
360 throws IOException, ServletException {
361
362 if (!isPortletRequest(request) && isLayout(request) &&
363 !isSignedIn(request) && !isInclude(request) &&
364 !isAlreadyFiltered(request)) {
365
366 request.setAttribute(SKIP_FILTER, Boolean.TRUE);
367
368 String key = getCacheKey(request);
369
370 long companyId = PortalInstances.getCompanyId(request);
371
372 CacheResponseData data = LayoutCacheUtil.getCacheResponseData(
373 companyId, key);
374
375 if (data == null) {
376 if (!isCacheable(companyId, request)) {
377 if (_log.isDebugEnabled()) {
378 _log.debug("Layout is not cacheable " + key);
379 }
380
381 processFilter(
382 LayoutCacheFilter.class, request, response,
383 filterChain);
384
385 return;
386 }
387
388 if (_log.isInfoEnabled()) {
389 _log.info("Caching layout " + key);
390 }
391
392 CacheResponse cacheResponse = new CacheResponse(
393 response, StringPool.UTF8);
394
395 processFilter(
396 LayoutCacheFilter.class, request, cacheResponse,
397 filterChain);
398
399 data = new CacheResponseData(
400 cacheResponse.getData(), cacheResponse.getContentType(),
401 cacheResponse.getHeaders());
402
403 LastPath lastPath = (LastPath)request.getAttribute(
404 WebKeys.LAST_PATH);
405
406 if (lastPath != null) {
407 data.setAttribute(WebKeys.LAST_PATH, lastPath);
408 }
409
410 if (data.getData().length > 0) {
411 LayoutCacheUtil.putCacheResponseData(companyId, key, data);
412 }
413 }
414 else {
415 LastPath lastPath = (LastPath)data.getAttribute(
416 WebKeys.LAST_PATH);
417
418 if (lastPath != null) {
419 HttpSession session = request.getSession();
420
421 session.setAttribute(WebKeys.LAST_PATH, lastPath);
422 }
423 }
424
425 CacheResponseUtil.write(response, data);
426 }
427 else {
428 if (_log.isDebugEnabled()) {
429 _log.debug("Did not request a layout");
430 }
431
432 processFilter(
433 LayoutCacheFilter.class, request, response, filterChain);
434 }
435 }
436
437 private static final int _PATTERN_FRIENDLY = 0;
438
439 private static final int _PATTERN_LAYOUT = 1;
440
441 private static final int _PATTERN_RESOURCE = 2;
442
443 private static final String _BROWSER_TYPE_IE_7 = "ie_7";
444
445 private static final String _BROWSER_TYPE_IE = "ie";
446
447 private static final String _BROWSER_TYPE_OTHER = "other";
448
449 private static Log _log = LogFactoryUtil.getLog(LayoutCacheFilter.class);
450
451 private int _pattern;
452
453 }