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