001
014
015 package com.liferay.portal.servlet.filters.dynamiccss;
016
017 import com.liferay.portal.kernel.log.Log;
018 import com.liferay.portal.kernel.log.LogFactoryUtil;
019 import com.liferay.portal.kernel.servlet.HttpHeaders;
020 import com.liferay.portal.kernel.servlet.ServletContextUtil;
021 import com.liferay.portal.kernel.servlet.ServletResponseUtil;
022 import com.liferay.portal.kernel.servlet.StringServletResponse;
023 import com.liferay.portal.kernel.util.CharPool;
024 import com.liferay.portal.kernel.util.ContentTypes;
025 import com.liferay.portal.kernel.util.FileUtil;
026 import com.liferay.portal.kernel.util.GetterUtil;
027 import com.liferay.portal.kernel.util.StringBundler;
028 import com.liferay.portal.kernel.util.StringPool;
029 import com.liferay.portal.kernel.util.StringUtil;
030 import com.liferay.portal.kernel.util.SystemProperties;
031 import com.liferay.portal.kernel.util.Validator;
032 import com.liferay.portal.kernel.util.WebKeys;
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 Object getDynamicContent(
070 HttpServletRequest request, HttpServletResponse response,
071 FilterChain filterChain)
072 throws Exception {
073
074 String requestURI = request.getRequestURI();
075
076 String requestPath = requestURI;
077
078 String contextPath = request.getContextPath();
079
080 if (!contextPath.equals(StringPool.SLASH)) {
081 requestPath = requestPath.substring(contextPath.length());
082 }
083
084 String realPath = ServletContextUtil.getRealPath(
085 _servletContext, requestPath);
086
087 if (realPath == null) {
088 return null;
089 }
090
091 realPath = StringUtil.replace(
092 realPath, CharPool.BACK_SLASH, CharPool.SLASH);
093
094 File file = new File(realPath);
095
096 if (!file.exists()) {
097 return null;
098 }
099
100 request.setAttribute(WebKeys.CSS_REAL_PATH, realPath);
101
102 StringBundler sb = new StringBundler(4);
103
104 sb.append(_tempDir);
105 sb.append(requestURI);
106
107 String queryString = request.getQueryString();
108
109 if (queryString != null) {
110 sb.append(_QUESTION_SEPARATOR);
111 sb.append(sterilizeQueryString(queryString));
112 }
113
114 String cacheCommonFileName = sb.toString();
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 String cssRealPath = (String)request.getAttribute(
137 WebKeys.CSS_REAL_PATH);
138
139 try {
140 if (realPath.endsWith(_CSS_EXTENSION)) {
141 if (_log.isInfoEnabled()) {
142 _log.info("Parsing SASS on CSS " + file);
143 }
144
145 content = FileUtil.read(file);
146
147 dynamicContent = DynamicCSSUtil.parseSass(
148 request, cssRealPath, content);
149
150 response.setContentType(ContentTypes.TEXT_CSS);
151
152 FileUtil.write(cacheContentTypeFile, ContentTypes.TEXT_CSS);
153 }
154 else if (realPath.endsWith(_JSP_EXTENSION)) {
155 if (_log.isInfoEnabled()) {
156 _log.info("Parsing SASS on JSP " + file);
157 }
158
159 StringServletResponse stringResponse =
160 new StringServletResponse(response);
161
162 processFilter(
163 DynamicCSSFilter.class, request, stringResponse,
164 filterChain);
165
166 CacheResponseUtil.setHeaders(
167 response, stringResponse.getHeaders());
168
169 response.setContentType(stringResponse.getContentType());
170
171 content = stringResponse.getString();
172
173 dynamicContent = DynamicCSSUtil.parseSass(
174 request, cssRealPath, content);
175
176 FileUtil.write(
177 cacheContentTypeFile, stringResponse.getContentType());
178 }
179 else {
180 return null;
181 }
182 }
183 catch (Exception e) {
184 _log.error("Unable to parse SASS on CSS " + cssRealPath, e);
185
186 if (_log.isDebugEnabled()) {
187 _log.debug(content);
188 }
189
190 response.setHeader(
191 HttpHeaders.CACHE_CONTROL,
192 HttpHeaders.CACHE_CONTROL_NO_CACHE_VALUE);
193 }
194
195 if (dynamicContent != null) {
196 FileUtil.write(cacheDataFile, dynamicContent);
197 }
198 else {
199 dynamicContent = content;
200 }
201
202 return dynamicContent;
203 }
204
205 @Override
206 protected void processFilter(
207 HttpServletRequest request, HttpServletResponse response,
208 FilterChain filterChain)
209 throws Exception {
210
211 Object parsedContent = getDynamicContent(
212 request, response, filterChain);
213
214 if (parsedContent == null) {
215 processFilter(
216 DynamicCSSFilter.class, request, response, filterChain);
217 }
218 else {
219 if (parsedContent instanceof File) {
220 ServletResponseUtil.write(response, (File)parsedContent);
221 }
222 else if (parsedContent instanceof String) {
223 ServletResponseUtil.write(response, (String)parsedContent);
224 }
225 }
226 }
227
228 protected String sterilizeQueryString(String queryString) {
229 return StringUtil.replace(
230 queryString,
231 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 _QUESTION_SEPARATOR = "_Q_";
240
241 private static final String _TEMP_DIR =
242 SystemProperties.get(SystemProperties.TMP_DIR) + "/liferay/css";
243
244 private static Log _log = LogFactoryUtil.getLog(DynamicCSSFilter.class);
245
246 private ServletContext _servletContext;
247 private String _servletContextName;
248 private String _tempDir = _TEMP_DIR;
249
250 }