001
014
015 package com.liferay.portal.servlet.filters.dynamiccss;
016
017 import com.liferay.portal.kernel.cache.key.CacheKeyGenerator;
018 import com.liferay.portal.kernel.cache.key.CacheKeyGeneratorUtil;
019 import com.liferay.portal.kernel.log.Log;
020 import com.liferay.portal.kernel.log.LogFactoryUtil;
021 import com.liferay.portal.kernel.servlet.HttpHeaders;
022 import com.liferay.portal.kernel.servlet.ServletContextUtil;
023 import com.liferay.portal.kernel.servlet.ServletResponseUtil;
024 import com.liferay.portal.kernel.servlet.StringServletResponse;
025 import com.liferay.portal.kernel.util.CharPool;
026 import com.liferay.portal.kernel.util.ContentTypes;
027 import com.liferay.portal.kernel.util.FileUtil;
028 import com.liferay.portal.kernel.util.GetterUtil;
029 import com.liferay.portal.kernel.util.StringPool;
030 import com.liferay.portal.kernel.util.StringUtil;
031 import com.liferay.portal.kernel.util.SystemProperties;
032 import com.liferay.portal.kernel.util.Validator;
033 import com.liferay.portal.servlet.filters.BasePortalFilter;
034 import com.liferay.portal.util.PropsUtil;
035 import com.liferay.util.servlet.filters.CacheResponseUtil;
036
037 import java.io.File;
038
039 import javax.servlet.FilterChain;
040 import javax.servlet.FilterConfig;
041 import javax.servlet.ServletContext;
042 import javax.servlet.http.HttpServletRequest;
043 import javax.servlet.http.HttpServletResponse;
044
045
049 public class DynamicCSSFilter extends BasePortalFilter {
050
051 public static final boolean ENABLED = GetterUtil.getBoolean(
052 PropsUtil.get(DynamicCSSFilter.class.getName()));
053
054 @Override
055 public void init(FilterConfig filterConfig) {
056 super.init(filterConfig);
057
058 _servletContext = filterConfig.getServletContext();
059 _servletContextName = GetterUtil.getString(
060 _servletContext.getServletContextName());
061
062 if (Validator.isNull(_servletContextName)) {
063 _tempDir += "/portal";
064 }
065
066 DynamicCSSUtil.init();
067 }
068
069 protected String getCacheFileName(HttpServletRequest request) {
070 CacheKeyGenerator cacheKeyGenerator =
071 CacheKeyGeneratorUtil.getCacheKeyGenerator(
072 DynamicCSSFilter.class.getName());
073
074 cacheKeyGenerator.append(request.getRequestURI());
075
076 String queryString = request.getQueryString();
077
078 if (queryString != null) {
079 cacheKeyGenerator.append(sterilizeQueryString(queryString));
080 }
081
082 String cacheKey = String.valueOf(cacheKeyGenerator.finish());
083
084 return _tempDir.concat(StringPool.SLASH).concat(cacheKey);
085 }
086
087 protected Object getDynamicContent(
088 HttpServletRequest request, HttpServletResponse response,
089 FilterChain filterChain)
090 throws Exception {
091
092 String requestURI = request.getRequestURI();
093
094 String requestPath = requestURI;
095
096 String contextPath = request.getContextPath();
097
098 if (!contextPath.equals(StringPool.SLASH)) {
099 requestPath = requestPath.substring(contextPath.length());
100 }
101
102 String realPath = ServletContextUtil.getRealPath(
103 _servletContext, requestPath);
104
105 if (realPath == null) {
106 return null;
107 }
108
109 realPath = StringUtil.replace(
110 realPath, CharPool.BACK_SLASH, CharPool.SLASH);
111
112 File file = new File(realPath);
113
114 if (!file.exists()) {
115 return null;
116 }
117
118 String cacheCommonFileName = getCacheFileName(request);
119
120 File cacheContentTypeFile = new File(
121 cacheCommonFileName + "_E_CONTENT_TYPE");
122 File cacheDataFile = new File(cacheCommonFileName + "_E_DATA");
123
124 if (cacheDataFile.exists() &&
125 (cacheDataFile.lastModified() >= file.lastModified())) {
126
127 if (cacheContentTypeFile.exists()) {
128 String contentType = FileUtil.read(cacheContentTypeFile);
129
130 response.setContentType(contentType);
131 }
132
133 return cacheDataFile;
134 }
135
136 String dynamicContent = null;
137
138 String content = null;
139
140 try {
141 if (realPath.endsWith(_CSS_EXTENSION) && file.exists()) {
142 if (_log.isInfoEnabled()) {
143 _log.info("Parsing SASS on CSS " + file);
144 }
145
146 content = FileUtil.read(file);
147
148 dynamicContent = DynamicCSSUtil.parseSass(
149 request, realPath, content);
150
151 response.setContentType(ContentTypes.TEXT_CSS);
152
153 FileUtil.write(cacheContentTypeFile, ContentTypes.TEXT_CSS);
154 }
155 else if (realPath.endsWith(_JSP_EXTENSION) || !file.exists()) {
156 if (_log.isInfoEnabled()) {
157 _log.info("Parsing SASS on JSP or servlet " + realPath);
158 }
159
160 StringServletResponse stringResponse =
161 new StringServletResponse(response);
162
163 processFilter(
164 DynamicCSSFilter.class, request, stringResponse,
165 filterChain);
166
167 CacheResponseUtil.setHeaders(
168 response, stringResponse.getHeaders());
169
170 response.setContentType(stringResponse.getContentType());
171
172 content = stringResponse.getString();
173
174 dynamicContent = DynamicCSSUtil.parseSass(
175 request, realPath, content);
176
177 FileUtil.write(
178 cacheContentTypeFile, stringResponse.getContentType());
179 }
180 else {
181 return null;
182 }
183 }
184 catch (Exception e) {
185 _log.error("Unable to parse SASS on CSS " + realPath, e);
186
187 if (_log.isDebugEnabled()) {
188 _log.debug(content);
189 }
190
191 response.setHeader(
192 HttpHeaders.CACHE_CONTROL,
193 HttpHeaders.CACHE_CONTROL_NO_CACHE_VALUE);
194 }
195
196 if (dynamicContent != null) {
197 FileUtil.write(cacheDataFile, dynamicContent);
198 }
199 else {
200 dynamicContent = content;
201 }
202
203 return dynamicContent;
204 }
205
206 @Override
207 protected void processFilter(
208 HttpServletRequest request, HttpServletResponse response,
209 FilterChain filterChain)
210 throws Exception {
211
212 Object parsedContent = getDynamicContent(
213 request, response, filterChain);
214
215 if (parsedContent == null) {
216 processFilter(
217 DynamicCSSFilter.class, request, response, filterChain);
218 }
219 else {
220 if (parsedContent instanceof File) {
221 ServletResponseUtil.write(response, (File)parsedContent);
222 }
223 else if (parsedContent instanceof String) {
224 ServletResponseUtil.write(response, (String)parsedContent);
225 }
226 }
227 }
228
229 protected String sterilizeQueryString(String queryString) {
230 return StringUtil.replace(
231 queryString, new String[] {StringPool.SLASH, StringPool.BACK_SLASH},
232 new String[] {StringPool.UNDERLINE, StringPool.UNDERLINE});
233 }
234
235 private static final String _CSS_EXTENSION = ".css";
236
237 private static final String _JSP_EXTENSION = ".jsp";
238
239 private static final String _TEMP_DIR =
240 SystemProperties.get(SystemProperties.TMP_DIR) + "/liferay/css";
241
242 private static Log _log = LogFactoryUtil.getLog(DynamicCSSFilter.class);
243
244 private ServletContext _servletContext;
245 private String _servletContextName;
246 private String _tempDir = _TEMP_DIR;
247
248 }