001
014
015 package com.liferay.portal.poller;
016
017 import com.liferay.portal.kernel.json.JSONFactoryUtil;
018 import com.liferay.portal.kernel.json.JSONObject;
019 import com.liferay.portal.kernel.log.Log;
020 import com.liferay.portal.kernel.log.LogFactoryUtil;
021 import com.liferay.portal.kernel.messaging.DestinationNames;
022 import com.liferay.portal.kernel.messaging.Message;
023 import com.liferay.portal.kernel.messaging.MessageBusUtil;
024 import com.liferay.portal.kernel.messaging.MessageListener;
025 import com.liferay.portal.kernel.poller.PollerHeader;
026 import com.liferay.portal.kernel.poller.PollerProcessor;
027 import com.liferay.portal.kernel.poller.PollerRequest;
028 import com.liferay.portal.kernel.poller.PollerResponse;
029 import com.liferay.portal.kernel.util.GetterUtil;
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.kernel.uuid.PortalUUIDUtil;
034 import com.liferay.portal.model.BrowserTracker;
035 import com.liferay.portal.model.Company;
036 import com.liferay.portal.service.BrowserTrackerLocalServiceUtil;
037 import com.liferay.portal.service.CompanyLocalServiceUtil;
038 import com.liferay.util.Encryptor;
039
040 import java.util.ArrayList;
041 import java.util.HashMap;
042 import java.util.HashSet;
043 import java.util.List;
044 import java.util.Map;
045 import java.util.Set;
046
047 import javax.servlet.http.HttpServletRequest;
048
049
054 public class PollerRequestHandlerImpl
055 implements PollerRequestHandler, MessageListener {
056
057 @Override
058 public PollerHeader getPollerHeader(String pollerRequestString) {
059 if (Validator.isNull(pollerRequestString)) {
060 return null;
061 }
062
063 Map<String, Object>[] pollerRequestChunks =
064 parsePollerRequestParameters(pollerRequestString);
065
066 return parsePollerRequestHeader(pollerRequestChunks);
067 }
068
069 @Override
070 public JSONObject processRequest(
071 HttpServletRequest request, String pollerRequestString)
072 throws Exception {
073
074 if (Validator.isNull(pollerRequestString)) {
075 return null;
076 }
077
078 Map<String, Object>[] pollerRequestChunks =
079 parsePollerRequestParameters(pollerRequestString);
080
081 PollerHeader pollerHeader = parsePollerRequestHeader(
082 pollerRequestChunks);
083
084 if (!isValidPollerHeader(pollerHeader)) {
085 if (_log.isWarnEnabled()) {
086 _log.warn(
087 "Invalid poller header for request " + pollerRequestString);
088 }
089
090 return null;
091 }
092
093 boolean receiveRequest = isReceiveRequest(request.getPathInfo());
094
095 String pollerSessionId = getPollerSessionId(pollerHeader);
096
097 PollerSession pollerSession = null;
098
099 synchronized (_pollerSessions) {
100 pollerSession = _pollerSessions.get(pollerSessionId);
101
102 if ((pollerSession == null) && receiveRequest) {
103 pollerSession = new PollerSession(pollerSessionId);
104
105 _pollerSessions.put(pollerSessionId, pollerSession);
106 }
107 }
108
109 List<PollerRequest> pollerRequests = createPollerRequests(
110 pollerHeader, pollerRequestChunks, receiveRequest);
111
112 executePollerRequests(pollerSession, pollerRequests);
113
114 if (receiveRequest) {
115 return createPollerResponseHeader(pollerHeader);
116 }
117 else {
118 return null;
119 }
120 }
121
122 @Override
123 public void receive(Message message) {
124 Object messagePayload = message.getPayload();
125
126 if (!(messagePayload instanceof PollerResponse)) {
127 return;
128 }
129
130 PollerResponse pollerResponse = (PollerResponse)messagePayload;
131
132 PollerHeader pollerHeader = pollerResponse.getPollerHeader();
133
134 String pollerSessionId = getPollerSessionId(pollerHeader);
135
136 synchronized (_pollerSessions) {
137 PollerSession pollerSession = _pollerSessions.get(pollerSessionId);
138
139 if ((pollerSession != null) &&
140 pollerSession.completePortletProcessing(
141 pollerResponse.getPortletId(), message.getResponseId())) {
142
143 _pollerSessions.remove(pollerSessionId);
144 }
145 }
146 }
147
148 protected PollerRequest createPollerRequest(
149 PollerHeader pollerHeader, String portletId, boolean receiveRequest)
150 throws Exception {
151
152 return createPollerRequest(
153 pollerHeader, portletId, new HashMap<String, String>(), null,
154 receiveRequest);
155 }
156
157 protected PollerRequest createPollerRequest(
158 PollerHeader pollerHeader, String portletId,
159 Map<String, String> parameterMap, String chunkId,
160 boolean receiveRequest)
161 throws Exception {
162
163 PollerProcessor pollerProcessor =
164 PollerProcessorUtil.getPollerProcessor(portletId);
165
166 if (pollerProcessor == null) {
167 if (_log.isWarnEnabled()) {
168 _log.warn(
169 "Poller processor not found for portlet " + portletId);
170 }
171
172 return null;
173 }
174
175 return new PollerRequest(
176 pollerHeader, portletId, parameterMap, chunkId, receiveRequest);
177 }
178
179 protected List<PollerRequest> createPollerRequests(
180 PollerHeader pollerHeader,
181 Map<String, Object>[] pollerRequestChunks, boolean receiveRequest)
182 throws Exception {
183
184 Map<String, Boolean> portletIdsMap = pollerHeader.getPortletIdsMap();
185
186 List<PollerRequest> pollerRequests = new ArrayList<>(
187 portletIdsMap.size());
188
189 Set<String> receiveRequestPortletIds = null;
190
191 if (receiveRequest) {
192 receiveRequestPortletIds = new HashSet<>(
193 (int)(pollerRequestChunks.length / 0.75) + 1);
194 }
195
196 for (int i = 1; i < pollerRequestChunks.length; i++) {
197 Map<String, Object> pollerRequestChunk = pollerRequestChunks[i];
198
199 String portletId = (String)pollerRequestChunk.get("portletId");
200 Map<String, String> parameterMap = parseData(pollerRequestChunk);
201 String chunkId = (String)pollerRequestChunk.get("chunkId");
202
203 try {
204 PollerRequest pollerRequest = createPollerRequest(
205 pollerHeader, portletId, parameterMap, chunkId,
206 receiveRequest);
207
208 pollerRequests.add(pollerRequest);
209
210 if (receiveRequest) {
211 receiveRequestPortletIds.add(portletId);
212 }
213 }
214 catch (Exception e) {
215 _log.error(e, e);
216 }
217 }
218
219 if (receiveRequest) {
220 Set<String> portletIds = portletIdsMap.keySet();
221
222 for (String portletId : portletIds) {
223 if (receiveRequestPortletIds.contains(portletId)) {
224 continue;
225 }
226
227 try {
228 PollerRequest pollerRequest = createPollerRequest(
229 pollerHeader, portletId, receiveRequest);
230
231 pollerRequests.add(pollerRequest);
232 }
233 catch (Exception e) {
234 _log.error(e, e);
235 }
236 }
237 }
238
239 return pollerRequests;
240 }
241
242 protected JSONObject createPollerResponseHeader(PollerHeader pollerHeader) {
243 if (pollerHeader == null) {
244 return null;
245 }
246
247 boolean suspendPolling = false;
248
249 if (pollerHeader.isStartPolling()) {
250 BrowserTrackerLocalServiceUtil.updateBrowserTracker(
251 pollerHeader.getUserId(), pollerHeader.getBrowserKey());
252 }
253 else {
254 BrowserTracker browserTracker =
255 BrowserTrackerLocalServiceUtil.getBrowserTracker(
256 pollerHeader.getUserId(), pollerHeader.getBrowserKey());
257
258 if (browserTracker.getBrowserKey() !=
259 pollerHeader.getBrowserKey()) {
260
261 suspendPolling = true;
262 }
263 }
264
265 JSONObject pollerResponseHeaderJSONObject =
266 JSONFactoryUtil.createJSONObject();
267
268 pollerResponseHeaderJSONObject.put("userId", pollerHeader.getUserId());
269 pollerResponseHeaderJSONObject.put("suspendPolling", suspendPolling);
270
271 return pollerResponseHeaderJSONObject;
272 }
273
274 protected void executePollerRequests(
275 PollerSession pollerSession, List<PollerRequest> pollerRequests) {
276
277 for (PollerRequest pollerRequest : pollerRequests) {
278 String responseId = null;
279
280 if (pollerRequest.isReceiveRequest()) {
281 responseId = PortalUUIDUtil.generate();
282
283 if (!pollerSession.beginPortletProcessing(
284 pollerRequest, responseId)) {
285
286 continue;
287 }
288 }
289
290 Message message = new Message();
291
292 message.setPayload(pollerRequest);
293
294 if (pollerRequest.isReceiveRequest()) {
295 message.setResponseId(responseId);
296
297 message.setResponseDestinationName(
298 DestinationNames.POLLER_RESPONSE);
299 }
300
301 MessageBusUtil.sendMessage(DestinationNames.POLLER, message);
302 }
303 }
304
305 protected String fixPollerRequestString(String pollerRequestString) {
306 if (Validator.isNull(pollerRequestString)) {
307 return null;
308 }
309
310 return StringUtil.replace(
311 pollerRequestString,
312 new String[] {
313 StringPool.OPEN_CURLY_BRACE, StringPool.CLOSE_CURLY_BRACE,
314 _ESCAPED_OPEN_CURLY_BRACE, _ESCAPED_CLOSE_CURLY_BRACE
315 },
316 new String[] {
317 _OPEN_HASH_MAP_WRAPPER, StringPool.DOUBLE_CLOSE_CURLY_BRACE,
318 StringPool.OPEN_CURLY_BRACE, StringPool.CLOSE_CURLY_BRACE
319 });
320 }
321
322 protected String getPollerSessionId(PollerHeader pollerHeader) {
323 return String.valueOf(pollerHeader.getUserId());
324 }
325
326 protected long getUserId(long companyId, String userIdString) {
327 long userId = 0;
328
329 try {
330 Company company = CompanyLocalServiceUtil.getCompany(companyId);
331
332 userId = GetterUtil.getLong(
333 Encryptor.decrypt(company.getKeyObj(), userIdString));
334 }
335 catch (Exception e) {
336 _log.error(
337 "Invalid credentials for company id " + companyId +
338 " and user id " + userIdString);
339 }
340
341 return userId;
342 }
343
344 protected boolean isReceiveRequest(String path) {
345 if ((path != null) && path.endsWith(_PATH_RECEIVE)) {
346 return true;
347 }
348 else {
349 return false;
350 }
351 }
352
353 protected boolean isValidPollerHeader(PollerHeader pollerHeader) {
354 if (pollerHeader == null) {
355 return false;
356 }
357
358 Map<String, Boolean> portletIdsMap = pollerHeader.getPortletIdsMap();
359
360 if ((portletIdsMap == null) || portletIdsMap.isEmpty()) {
361 return false;
362 }
363
364 return true;
365 }
366
367 protected Map<String, String> parseData(
368 Map<String, Object> pollerRequestChunk)
369 throws Exception {
370
371 Map<String, Object> oldParameterMap =
372 (Map<String, Object>)pollerRequestChunk.get("data");
373
374 Map<String, String> newParameterMap = new HashMap<>();
375
376 if (oldParameterMap == null) {
377 return newParameterMap;
378 }
379
380 for (Map.Entry<String, Object> entry : oldParameterMap.entrySet()) {
381 newParameterMap.put(
382 entry.getKey(), String.valueOf(entry.getValue()));
383 }
384
385 return newParameterMap;
386 }
387
388 protected PollerHeader parsePollerRequestHeader(
389 Map<String, Object>[] pollerRequestChunks) {
390
391 if ((pollerRequestChunks == null) || (pollerRequestChunks.length < 1)) {
392 return null;
393 }
394
395 Map<String, Object> pollerRequestChunk = pollerRequestChunks[0];
396
397 long browserKey = GetterUtil.getLong(
398 String.valueOf(pollerRequestChunk.get("browserKey")));
399 long companyId = GetterUtil.getLong(
400 String.valueOf(pollerRequestChunk.get("companyId")));
401 Map<String, Boolean> portletIdsMap =
402 (Map<String, Boolean>)pollerRequestChunk.get("portletIdsMap");
403 boolean startPolling = GetterUtil.getBoolean(
404 String.valueOf(pollerRequestChunk.get("startPolling")));
405 String userIdString = GetterUtil.getString(
406 String.valueOf(pollerRequestChunk.get("userId")));
407
408 long userId = getUserId(companyId, userIdString);
409
410 if (userId == 0) {
411 return null;
412 }
413
414 return new PollerHeader(
415 companyId, userId, browserKey, portletIdsMap, startPolling);
416 }
417
418 protected Map<String, Object>[] parsePollerRequestParameters(
419 String pollerRequestString) {
420
421 String fixedPollerRequestString = fixPollerRequestString(
422 pollerRequestString);
423
424 return (Map<String, Object>[])JSONFactoryUtil.deserialize(
425 fixedPollerRequestString);
426 }
427
428 private static final String _ESCAPED_CLOSE_CURLY_BRACE =
429 "[$CLOSE_CURLY_BRACE$]";
430
431 private static final String _ESCAPED_OPEN_CURLY_BRACE =
432 "[$OPEN_CURLY_BRACE$]";
433
434 private static final String _OPEN_HASH_MAP_WRAPPER =
435 "{\"javaClass\":\"java.util.HashMap\",\"map\":{";
436
437 private static final String _PATH_RECEIVE = "/receive";
438
439 private static final Log _log = LogFactoryUtil.getLog(
440 PollerRequestHandlerImpl.class);
441
442 private final Map<String, PollerSession> _pollerSessions = new HashMap<>();
443
444 }