/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.servlet.filters.dynamiccss;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.servlet.BufferCacheServletResponse;
import com.liferay.portal.kernel.servlet.DynamicResourceIncludeUtil;
import com.liferay.portal.kernel.servlet.HttpHeaders;
import com.liferay.portal.kernel.servlet.PortalWebResourcesUtil;
import com.liferay.portal.kernel.servlet.PortletResourcesUtil;
import com.liferay.portal.kernel.servlet.ServletResponseUtil;
import com.liferay.portal.kernel.util.ContentTypes;
import com.liferay.portal.kernel.util.FileUtil;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.JavaConstants;
import com.liferay.portal.kernel.util.ParamUtil;
import com.liferay.portal.kernel.util.PortalUtil;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.URLUtil;
import com.liferay.portal.servlet.filters.IgnoreModuleRequestFilter;
import com.liferay.portal.servlet.filters.util.CacheFileNameGenerator;
import com.liferay.portal.util.PropsUtil;
import java.io.File;
import java.net.URL;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author Eduardo Lundgren
* @author Raymond Augé
*/
public class DynamicCSSFilter extends IgnoreModuleRequestFilter {
public static final boolean ENABLED = GetterUtil.getBoolean(
PropsUtil.get(DynamicCSSFilter.class.getName()));
@Override
public void init(FilterConfig filterConfig) {
super.init(filterConfig);
_servletContext = filterConfig.getServletContext();
File tempDir = (File)_servletContext.getAttribute(
JavaConstants.JAVAX_SERVLET_CONTEXT_TEMPDIR);
_tempDir = new File(tempDir, _TEMP_DIR);
_tempDir.mkdirs();
}
protected String getCacheFileName(HttpServletRequest request) {
String[] cacheKeyKeys = null;
if (PortalUtil.isRightToLeft(request)) {
cacheKeyKeys = _CACHE_KEY_APPEND_KEYS;
}
return _cacheFileNameGenerator.getCacheFileName(
DynamicCSSFilter.class, request, _REMOVE_PARAMETER_NAMES,
cacheKeyKeys);
}
protected Object getDynamicContent(
HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain)
throws Exception {
ServletContext servletContext = _servletContext;
String requestPath = getRequestPath(request);
if (requestPath.endsWith(_CSS_EXTENSION) &&
PortalUtil.isRightToLeft(request)) {
int pos = requestPath.lastIndexOf(StringPool.PERIOD);
requestPath =
requestPath.substring(0, pos) + "_rtl" +
requestPath.substring(pos);
}
URL resourceURL = _servletContext.getResource(requestPath);
if (resourceURL == null) {
ServletContext resourceServletContext =
PortalWebResourcesUtil.getPathServletContext(requestPath);
if (resourceServletContext != null) {
resourceURL = PortalWebResourcesUtil.getResource(
resourceServletContext, requestPath);
}
if (resourceURL == null) {
resourceServletContext =
PortletResourcesUtil.getPathServletContext(requestPath);
if (resourceServletContext != null) {
resourceURL = PortletResourcesUtil.getResource(
resourceServletContext, requestPath);
}
}
if (resourceURL == null) {
resourceServletContext =
DynamicResourceIncludeUtil.getPathServletContext(
requestPath);
if (resourceServletContext != null) {
resourceURL = DynamicResourceIncludeUtil.getResource(
resourceServletContext, requestPath);
}
}
if (resourceURL == null) {
return null;
}
servletContext = resourceServletContext;
}
String cacheCommonFileName = getCacheFileName(request);
File cacheContentTypeFile = new File(
_tempDir, cacheCommonFileName + "_E_CTYPE");
File cacheDataFile = new File(
_tempDir, cacheCommonFileName + "_E_DATA");
if (cacheDataFile.exists() &&
(cacheDataFile.lastModified() >=
getLastModified(request, resourceURL))) {
if (cacheContentTypeFile.exists()) {
String contentType = FileUtil.read(cacheContentTypeFile);
response.setContentType(contentType);
}
return cacheDataFile;
}
String dynamicContent = null;
String content = null;
try {
if (requestPath.endsWith(_CSS_EXTENSION)) {
if (_log.isInfoEnabled()) {
_log.info("Replacing tokens on CSS " + requestPath);
}
content = StringUtil.read(resourceURL.openStream());
dynamicContent = DynamicCSSUtil.replaceToken(
servletContext, request, content);
response.setContentType(ContentTypes.TEXT_CSS);
FileUtil.write(cacheContentTypeFile, ContentTypes.TEXT_CSS);
}
else if (requestPath.endsWith(_JSP_EXTENSION)) {
if (_log.isInfoEnabled()) {
_log.info(
"Replacing tokens on JSP or servlet " + requestPath);
}
BufferCacheServletResponse bufferCacheServletResponse =
new BufferCacheServletResponse(response);
processFilter(
DynamicCSSFilter.class.getName(), request,
bufferCacheServletResponse, filterChain);
bufferCacheServletResponse.finishResponse(false);
content = bufferCacheServletResponse.getString();
dynamicContent = DynamicCSSUtil.replaceToken(
servletContext, request, content);
FileUtil.write(
cacheContentTypeFile,
bufferCacheServletResponse.getContentType());
}
else {
return null;
}
}
catch (Exception e) {
_log.error("Unable to replace tokens in CSS " + requestPath, e);
if (_log.isDebugEnabled()) {
_log.debug(content);
}
response.setHeader(
HttpHeaders.CACHE_CONTROL,
HttpHeaders.CACHE_CONTROL_NO_CACHE_VALUE);
}
if (dynamicContent != null) {
FileUtil.write(cacheDataFile, dynamicContent);
}
else {
dynamicContent = content;
}
return dynamicContent;
}
protected long getLastModified(HttpServletRequest request, URL resourceURL)
throws Exception {
long resourceLastModified = URLUtil.getLastModifiedTime(resourceURL);
long requestLastModified = ParamUtil.getLong(request, "t", -1);
return Math.max(resourceLastModified, requestLastModified);
}
protected String getRequestPath(HttpServletRequest request) {
String requestPath = request.getRequestURI();
String contextPath = request.getContextPath();
if (!contextPath.equals(StringPool.SLASH)) {
requestPath = requestPath.substring(contextPath.length());
}
return requestPath;
}
@Override
protected boolean isModuleRequest(HttpServletRequest request) {
String requestURI = request.getRequestURI();
if (PortalWebResourcesUtil.hasContextPath(requestURI)) {
return false;
}
return super.isModuleRequest(request);
}
@Override
protected void processFilter(
HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain)
throws Exception {
Object parsedContent = getDynamicContent(
request, response, filterChain);
if (parsedContent == null) {
processFilter(
DynamicCSSFilter.class.getName(), request, response,
filterChain);
}
else {
if (parsedContent instanceof File) {
ServletResponseUtil.write(response, (File)parsedContent);
}
else if (parsedContent instanceof String) {
ServletResponseUtil.write(response, (String)parsedContent);
}
}
}
private static final String[] _CACHE_KEY_APPEND_KEYS = {"_rtl"};
private static final String _CSS_EXTENSION = ".css";
private static final String _JSP_EXTENSION = ".jsp";
private static final String[] _REMOVE_PARAMETER_NAMES = {"zx"};
private static final String _TEMP_DIR = "css";
private static final Log _log = LogFactoryUtil.getLog(
DynamicCSSFilter.class);
private final CacheFileNameGenerator _cacheFileNameGenerator =
new CacheFileNameGenerator();
private ServletContext _servletContext;
private File _tempDir;
}