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