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