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