001
014
015 package com.liferay.portal.poller;
016
017 import com.liferay.portal.NoSuchLayoutException;
018 import com.liferay.portal.kernel.json.JSONArray;
019 import com.liferay.portal.kernel.json.JSONFactoryUtil;
020 import com.liferay.portal.kernel.json.JSONObject;
021 import com.liferay.portal.kernel.log.Log;
022 import com.liferay.portal.kernel.log.LogFactoryUtil;
023 import com.liferay.portal.kernel.messaging.DestinationNames;
024 import com.liferay.portal.kernel.poller.PollerHeader;
025 import com.liferay.portal.kernel.poller.PollerProcessor;
026 import com.liferay.portal.kernel.poller.PollerRequest;
027 import com.liferay.portal.kernel.util.ContentTypes;
028 import com.liferay.portal.kernel.util.GetterUtil;
029 import com.liferay.portal.kernel.util.ParamUtil;
030 import com.liferay.portal.kernel.util.StringPool;
031 import com.liferay.portal.kernel.util.StringUtil;
032 import com.liferay.portal.kernel.util.Validator;
033 import com.liferay.portal.model.BrowserTracker;
034 import com.liferay.portal.model.Company;
035 import com.liferay.portal.service.BrowserTrackerLocalServiceUtil;
036 import com.liferay.portal.service.CompanyLocalServiceUtil;
037 import com.liferay.portal.util.PortalUtil;
038 import com.liferay.portal.util.PropsValues;
039 import com.liferay.util.Encryptor;
040 import com.liferay.util.servlet.ServletResponseUtil;
041
042 import java.io.IOException;
043
044 import java.util.HashMap;
045 import java.util.HashSet;
046 import java.util.Map;
047 import java.util.Set;
048
049 import javax.servlet.ServletException;
050 import javax.servlet.http.HttpServlet;
051 import javax.servlet.http.HttpServletRequest;
052 import javax.servlet.http.HttpServletResponse;
053
054
057 public class PollerServlet extends HttpServlet {
058
059 public void service(
060 HttpServletRequest request, HttpServletResponse response)
061 throws IOException, ServletException {
062
063 try {
064 String content = getContent(request);
065
066 if (content == null) {
067 PortalUtil.sendError(
068 HttpServletResponse.SC_NOT_FOUND,
069 new NoSuchLayoutException(), request, response);
070 }
071 else {
072 response.setContentType(ContentTypes.TEXT_PLAIN_UTF8);
073
074 ServletResponseUtil.write(
075 response, content.getBytes(StringPool.UTF8));
076 }
077 }
078 catch (Exception e) {
079 _log.error(e, e);
080
081 PortalUtil.sendError(
082 HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e, request,
083 response);
084 }
085 }
086
087 protected String getContent(HttpServletRequest request) throws Exception {
088 String pollerRequestString = getPollerRequestString(request);
089
090 if (Validator.isNull(pollerRequestString)) {
091 return null;
092 }
093
094 Map<String, Object>[] pollerRequestChunks =
095 (Map<String, Object>[])JSONFactoryUtil.deserialize(
096 pollerRequestString);
097
098 PollerHeader pollerHeader = getPollerHeader(pollerRequestChunks);
099
100 if (pollerHeader == null) {
101 return null;
102 }
103
104 boolean receiveRequest = isReceiveRequest(request);
105
106 JSONArray pollerResponseChunksJSON = null;
107 Set<String> portletIdsWithChunks = null;
108
109 if (receiveRequest) {
110 pollerResponseChunksJSON = JSONFactoryUtil.createJSONArray();
111 portletIdsWithChunks = new HashSet<String>();
112
113 boolean suspendPolling = false;
114
115 if (pollerHeader.isStartPolling()) {
116 BrowserTrackerLocalServiceUtil.updateBrowserTracker(
117 pollerHeader.getUserId(), pollerHeader.getBrowserKey());
118 }
119 else {
120 BrowserTracker browserTracker =
121 BrowserTrackerLocalServiceUtil.getBrowserTracker(
122 pollerHeader.getUserId(), pollerHeader.getBrowserKey());
123
124 if (browserTracker.getBrowserKey() !=
125 pollerHeader.getBrowserKey()) {
126
127 suspendPolling = true;
128 }
129 }
130
131 JSONObject pollerResponseChunkJSON =
132 JSONFactoryUtil.createJSONObject();
133
134 pollerResponseChunkJSON.put("userId", pollerHeader.getUserId());
135 pollerResponseChunkJSON.put(
136 "initialRequest", pollerHeader.isInitialRequest());
137 pollerResponseChunkJSON.put("suspendPolling", suspendPolling);
138
139 pollerResponseChunksJSON.put(pollerResponseChunkJSON);
140 }
141
142 PollerRequestManager pollerRequestManager = new PollerRequestManager(
143 pollerResponseChunksJSON, DestinationNames.POLLER,
144 DestinationNames.POLLER_RESPONSE,
145 PropsValues.POLLER_REQUEST_TIMEOUT);
146
147 for (int i = 1; i < pollerRequestChunks.length; i++) {
148 Map<String, Object> pollerRequestChunk = pollerRequestChunks[i];
149
150 String portletId = (String)pollerRequestChunk.get("portletId");
151 Map<String, String> parameterMap = getData(pollerRequestChunk);
152 String chunkId = (String)pollerRequestChunk.get("chunkId");
153
154 try {
155 PollerRequest pollerRequest = process(
156 portletIdsWithChunks, pollerHeader, portletId, parameterMap,
157 chunkId, receiveRequest);
158
159 pollerRequestManager.addPollerRequest(pollerRequest);
160 }
161 catch (Exception e) {
162 _log.error(e, e);
163 }
164 }
165
166 pollerRequestManager.processRequests();
167
168 if (!receiveRequest) {
169 return StringPool.BLANK;
170 }
171
172 pollerRequestManager.clearRequests();
173
174 for (String portletId : pollerHeader.getPortletIds()) {
175 if (portletIdsWithChunks.contains(portletId)) {
176 continue;
177 }
178
179 try {
180 PollerRequest pollerRequest = process(
181 portletIdsWithChunks, pollerHeader, portletId,
182 new HashMap<String, String>(), null, receiveRequest);
183
184 pollerRequestManager.addPollerRequest(pollerRequest);
185 }
186 catch (Exception e) {
187 _log.error(e, e);
188 }
189 }
190
191 pollerRequestManager.processRequests();
192
193 pollerResponseChunksJSON = pollerRequestManager.getPollerResponse();
194
195 return pollerResponseChunksJSON.toString();
196 }
197
198 protected Map<String, String> getData(
199 Map<String, Object> pollerRequestChunk)
200 throws Exception {
201
202 Map<String, Object> oldParameterMap =
203 (Map<String, Object>)pollerRequestChunk.get("data");
204
205 Map<String, String> newParameterMap = new HashMap<String, String>();
206
207 if (oldParameterMap == null) {
208 return newParameterMap;
209 }
210
211 for (Map.Entry<String, Object> entry : oldParameterMap.entrySet()) {
212 newParameterMap.put(
213 entry.getKey(), String.valueOf(entry.getValue()));
214 }
215
216 return newParameterMap;
217 }
218
219 protected PollerHeader getPollerHeader(
220 Map<String, Object>[] pollerRequestChunks)
221 throws Exception {
222
223 if (pollerRequestChunks.length < 1) {
224 return null;
225 }
226
227 Map<String, Object> pollerRequestChunk = pollerRequestChunks[0];
228
229 long companyId = GetterUtil.getLong(
230 String.valueOf(pollerRequestChunk.get("companyId")));
231 String userIdString = GetterUtil.getString(
232 String.valueOf(pollerRequestChunk.get("userId")));
233 long browserKey = GetterUtil.getLong(
234 String.valueOf(pollerRequestChunk.get("browserKey")));
235 String[] portletIds = StringUtil.split(
236 String.valueOf(pollerRequestChunk.get("portletIds")));
237 boolean initialRequest = GetterUtil.getBoolean(
238 String.valueOf(pollerRequestChunk.get("initialRequest")));
239 boolean startPolling = GetterUtil.getBoolean(
240 String.valueOf(pollerRequestChunk.get("startPolling")));
241
242 long userId = getUserId(companyId, userIdString);
243
244 if (userId == 0) {
245 return null;
246 }
247
248 return new PollerHeader(
249 companyId, userId, browserKey, portletIds, initialRequest,
250 startPolling);
251 }
252
253 protected String getPollerRequestString(HttpServletRequest request)
254 throws Exception {
255
256 String pollerRequestString = ParamUtil.getString(
257 request, "pollerRequest");
258
259 if (Validator.isNull(pollerRequestString)) {
260 return null;
261 }
262
263 return StringUtil.replace(
264 pollerRequestString,
265 new String[] {
266 StringPool.OPEN_CURLY_BRACE,
267 StringPool.CLOSE_CURLY_BRACE,
268 _ESCAPED_OPEN_CURLY_BRACE,
269 _ESCAPED_CLOSE_CURLY_BRACE
270 },
271 new String[] {
272 _OPEN_HASH_MAP_WRAPPER,
273 StringPool.DOUBLE_CLOSE_CURLY_BRACE,
274 StringPool.OPEN_CURLY_BRACE,
275 StringPool.CLOSE_CURLY_BRACE
276 });
277 }
278
279 protected long getUserId(long companyId, String userIdString) {
280 long userId = 0;
281
282 try {
283 Company company = CompanyLocalServiceUtil.getCompany(companyId);
284
285 userId = GetterUtil.getLong(
286 Encryptor.decrypt(company.getKeyObj(), userIdString));
287 }
288 catch (Exception e) {
289 _log.error(
290 "Invalid credentials for company id " + companyId +
291 " and user id " + userIdString);
292 }
293
294 return userId;
295 }
296
297 protected boolean isReceiveRequest(HttpServletRequest request)
298 throws Exception {
299
300 String path = GetterUtil.getString(request.getPathInfo());
301
302 if (path.endsWith(_PATH_RECEIVE)) {
303 return true;
304 }
305 else {
306 return false;
307 }
308 }
309
310 protected PollerRequest process(
311 Set<String> portletIdsWithChunks, PollerHeader pollerHeader,
312 String portletId, Map<String, String> parameterMap, String chunkId,
313 boolean receiveRequest)
314 throws Exception {
315
316 PollerProcessor pollerProcessor =
317 PollerProcessorUtil.getPollerProcessor(portletId);
318
319 if (pollerProcessor == null) {
320 _log.error("Poller processor not found for portlet " + portletId);
321
322 return null;
323 }
324
325 PollerRequest pollerRequest = new PollerRequest(
326 pollerHeader, portletId, parameterMap, chunkId, receiveRequest);
327
328 if (receiveRequest) {
329 portletIdsWithChunks.add(portletId);
330 }
331
332 return pollerRequest;
333 }
334
335 private static final String _ESCAPED_CLOSE_CURLY_BRACE =
336 "[$CLOSE_CURLY_BRACE$]";
337
338 private static final String _ESCAPED_OPEN_CURLY_BRACE =
339 "[$OPEN_CURLY_BRACE$]";
340
341 private static final String _OPEN_HASH_MAP_WRAPPER =
342 "{\"javaClass\":\"java.util.HashMap\",\"map\":{";
343
344 private static final String _PATH_RECEIVE = "/receive";
345
346 private static Log _log = LogFactoryUtil.getLog(PollerServlet.class);
347
348 }