001
014
015 package com.liferay.portal.servlet;
016
017 import com.liferay.portal.kernel.servlet.ServletContextUtil;
018 import com.liferay.portal.kernel.util.ContentTypes;
019 import com.liferay.portal.kernel.util.FileUtil;
020 import com.liferay.portal.kernel.util.ParamUtil;
021 import com.liferay.portal.kernel.util.StringPool;
022 import com.liferay.portal.kernel.util.StringUtil;
023 import com.liferay.portal.kernel.util.Validator;
024 import com.liferay.portal.util.MinifierUtil;
025 import com.liferay.portal.util.PortalUtil;
026 import com.liferay.portal.util.PropsValues;
027 import com.liferay.util.servlet.ServletResponseUtil;
028
029 import java.io.File;
030 import java.io.IOException;
031
032 import java.util.concurrent.ConcurrentHashMap;
033 import java.util.concurrent.ConcurrentMap;
034
035 import javax.servlet.ServletContext;
036 import javax.servlet.http.HttpServlet;
037 import javax.servlet.http.HttpServletRequest;
038 import javax.servlet.http.HttpServletResponse;
039
040
043 public class ComboServlet extends HttpServlet {
044
045 public void service(
046 HttpServletRequest request, HttpServletResponse response)
047 throws IOException {
048
049 String contextPath = PortalUtil.getPathContext();
050
051 String[] modulePaths = request.getParameterValues("m");
052
053 if ((modulePaths == null) || (modulePaths.length == 0)) {
054 response.sendError(HttpServletResponse.SC_BAD_REQUEST);
055
056 return;
057 }
058
059 String p = ParamUtil.getString(request, "p");
060 String minifierType = ParamUtil.getString(request, "minifierType");
061
062 int length = modulePaths.length;
063
064 byte[][] bytesArray = new byte[length][];
065
066 for (String modulePath : modulePaths) {
067 byte[] bytes = new byte[0];
068
069 if (Validator.isNotNull(modulePath)) {
070 modulePath = StringUtil.replaceFirst(
071 p.concat(modulePath), contextPath, StringPool.BLANK);
072
073 bytes = getFileContent(modulePath, minifierType);
074 }
075
076 bytesArray[--length] = bytes;
077 }
078
079 String contentType = ContentTypes.TEXT_JAVASCRIPT;
080
081 String firstModulePath =
082 (String)request.getParameterNames().nextElement();
083
084 String extension = FileUtil.getExtension(firstModulePath);
085
086 if (extension.equalsIgnoreCase(_CSS_EXTENSION)) {
087 contentType = ContentTypes.TEXT_CSS;
088 }
089
090 response.setContentType(contentType);
091
092 ServletResponseUtil.write(response, bytesArray);
093 }
094
095 protected File getFile(String path) throws IOException {
096 ServletContext servletContext = getServletContext();
097
098 String basePath = ServletContextUtil.getRealPath(
099 servletContext, _JAVASCRIPT_DIR);
100
101 if (basePath == null) {
102 return null;
103 }
104
105 basePath = StringUtil.replace(
106 basePath, StringPool.BACK_SLASH, StringPool.SLASH);
107
108 File baseDir = new File(basePath);
109
110 if (!baseDir.exists()) {
111 return null;
112 }
113
114 String filePath = ServletContextUtil.getRealPath(servletContext, path);
115
116 if (filePath == null) {
117 return null;
118 }
119
120 filePath = StringUtil.replace(
121 filePath, StringPool.BACK_SLASH, StringPool.SLASH);
122
123 File file = new File(filePath);
124
125 if (!file.exists()) {
126 return null;
127 }
128
129 String baseCanonicalPath = baseDir.getCanonicalPath();
130 String fileCanonicalPath = file.getCanonicalPath();
131
132 if (fileCanonicalPath.indexOf(baseCanonicalPath) == 0) {
133 return file;
134 }
135
136 return null;
137 }
138
139 protected byte[] getFileContent(String path, String minifierType)
140 throws IOException {
141
142 String fileContentKey = path.concat(StringPool.QUESTION).concat(
143 minifierType);
144
145 FileContentBag fileContentBag = _fileContents.get(fileContentKey);
146
147 if ((fileContentBag != null) &&
148 !PropsValues.COMBO_CHECK_TIMESTAMP) {
149
150 return fileContentBag._fileContent;
151 }
152
153 File file = getFile(path);
154
155 if ((fileContentBag != null) && PropsValues.COMBO_CHECK_TIMESTAMP) {
156 if ((file != null) &&
157 (file.lastModified() == fileContentBag._lastModified)) {
158
159 return fileContentBag._fileContent;
160 }
161 else {
162 _fileContents.remove(fileContentKey, fileContentBag);
163 }
164 }
165
166 if (file == null) {
167 fileContentBag = _EMPTY_FILE_CONTENT_BAG;
168 }
169 else {
170 String stringFileContent = FileUtil.read(file);
171
172 if (!StringUtil.endsWith(path, _CSS_MINIFIED_SUFFIX) &&
173 !StringUtil.endsWith(path, _JAVASCRIPT_MINIFIED_SUFFIX)) {
174
175 if (minifierType.equals("css")) {
176 stringFileContent = MinifierUtil.minifyCss(
177 stringFileContent);
178 }
179 else if (minifierType.equals("js")) {
180 stringFileContent = MinifierUtil.minifyJavaScript(
181 stringFileContent);
182 }
183 }
184
185 fileContentBag = new FileContentBag(
186 stringFileContent.getBytes(StringPool.UTF8),
187 file.lastModified());
188 }
189
190 FileContentBag oldFileContentBag = _fileContents.putIfAbsent(
191 fileContentKey, fileContentBag);
192
193 if (oldFileContentBag != null) {
194 fileContentBag = oldFileContentBag;
195 }
196
197 return fileContentBag._fileContent;
198 }
199
200 private static final String _CSS_EXTENSION = "css";
201
202 private static final String _CSS_MINIFIED_SUFFIX = "-min.css";
203
204 private static final FileContentBag _EMPTY_FILE_CONTENT_BAG =
205 new FileContentBag(new byte[0], 0);
206
207 private static final String _JAVASCRIPT_DIR = "html/js";
208
209 private static final String _JAVASCRIPT_MINIFIED_SUFFIX = "-min.js";
210
211 private ConcurrentMap<String, FileContentBag> _fileContents =
212 new ConcurrentHashMap<String, FileContentBag>();
213
214 private static class FileContentBag {
215
216 public FileContentBag(byte[] fileContent, long lastModifiedTime) {
217 _fileContent = fileContent;
218 _lastModified = lastModifiedTime;
219 }
220
221 private byte[] _fileContent;
222 private long _lastModified;
223
224 }
225
226 }