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