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 String cacheCommonFileName = getCacheFileName(request);
115
116 File cacheContentTypeFile = new File(
117 cacheCommonFileName + "_E_CONTENT_TYPE");
118 File cacheDataFile = new File(cacheCommonFileName + "_E_DATA");
119
120 if ((cacheDataFile.exists()) &&
121 (cacheDataFile.lastModified() >= file.lastModified())) {
122
123 if (cacheContentTypeFile.exists()) {
124 String contentType = FileUtil.read(cacheContentTypeFile);
125
126 response.setContentType(contentType);
127 }
128
129 return cacheDataFile;
130 }
131
132 String dynamicContent = null;
133
134 String content = null;
135
136 try {
137 if (realPath.endsWith(_CSS_EXTENSION) && file.exists()) {
138 if (_log.isInfoEnabled()) {
139 _log.info("Parsing SASS on CSS " + file);
140 }
141
142 content = FileUtil.read(file);
143
144 dynamicContent = DynamicCSSUtil.parseSass(
145 request, realPath, content);
146
147 response.setContentType(ContentTypes.TEXT_CSS);
148
149 FileUtil.write(cacheContentTypeFile, ContentTypes.TEXT_CSS);
150 }
151 else if (realPath.endsWith(_JSP_EXTENSION) || !file.exists()) {
152 if (_log.isInfoEnabled()) {
153 _log.info("Parsing SASS on JSP or servlet " + realPath);
154 }
155
156 StringServletResponse stringResponse =
157 new StringServletResponse(response);
158
159 processFilter(
160 DynamicCSSFilter.class, request, stringResponse,
161 filterChain);
162
163 CacheResponseUtil.setHeaders(
164 response, stringResponse.getHeaders());
165
166 response.setContentType(stringResponse.getContentType());
167
168 content = stringResponse.getString();
169
170 dynamicContent = DynamicCSSUtil.parseSass(
171 request, realPath, content);
172
173 FileUtil.write(
174 cacheContentTypeFile, stringResponse.getContentType());
175 }
176 else {
177 return null;
178 }
179 }
180 catch (Exception e) {
181 _log.error("Unable to parse SASS on CSS " + realPath, e);
182
183 if (_log.isDebugEnabled()) {
184 _log.debug(content);
185 }
186
187 response.setHeader(
188 HttpHeaders.CACHE_CONTROL,
189 HttpHeaders.CACHE_CONTROL_NO_CACHE_VALUE);
190 }
191
192 if (dynamicContent != null) {
193 FileUtil.write(cacheDataFile, dynamicContent);
194 }
195 else {
196 dynamicContent = content;
197 }
198
199 return dynamicContent;
200 }
201
202 @Override
203 protected void processFilter(
204 HttpServletRequest request, HttpServletResponse response,
205 FilterChain filterChain)
206 throws Exception {
207
208 Object parsedContent = getDynamicContent(
209 request, response, filterChain);
210
211 if (parsedContent == null) {
212 processFilter(
213 DynamicCSSFilter.class, request, response, filterChain);
214 }
215 else {
216 if (parsedContent instanceof File) {
217 ServletResponseUtil.write(response, (File)parsedContent);
218 }
219 else if (parsedContent instanceof String) {
220 ServletResponseUtil.write(response, (String)parsedContent);
221 }
222 }
223 }
224
225 protected String sterilizeQueryString(String queryString) {
226 return StringUtil.replace(
227 queryString,
228 new String[] {StringPool.SLASH, StringPool.BACK_SLASH},
229 new String[] {StringPool.UNDERLINE, StringPool.UNDERLINE});
230 }
231
232 private static final String _CSS_EXTENSION = ".css";
233
234 private static final String _JSP_EXTENSION = ".jsp";
235
236 private static final String _TEMP_DIR =
237 SystemProperties.get(SystemProperties.TMP_DIR) + "/liferay/css";
238
239 private static Log _log = LogFactoryUtil.getLog(DynamicCSSFilter.class);
240
241 private ServletContext _servletContext;
242 private String _servletContextName;
243 private String _tempDir = _TEMP_DIR;
244
245 }