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