1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   *
13   */
14  
15  package com.liferay.portal.poller;
16  
17  import com.liferay.portal.NoSuchLayoutException;
18  import com.liferay.portal.kernel.json.JSONArray;
19  import com.liferay.portal.kernel.json.JSONFactoryUtil;
20  import com.liferay.portal.kernel.json.JSONObject;
21  import com.liferay.portal.kernel.log.Log;
22  import com.liferay.portal.kernel.log.LogFactoryUtil;
23  import com.liferay.portal.kernel.messaging.DestinationNames;
24  import com.liferay.portal.kernel.poller.PollerHeader;
25  import com.liferay.portal.kernel.poller.PollerProcessor;
26  import com.liferay.portal.kernel.poller.PollerRequest;
27  import com.liferay.portal.kernel.util.ContentTypes;
28  import com.liferay.portal.kernel.util.GetterUtil;
29  import com.liferay.portal.kernel.util.ParamUtil;
30  import com.liferay.portal.kernel.util.StringPool;
31  import com.liferay.portal.kernel.util.StringUtil;
32  import com.liferay.portal.kernel.util.Validator;
33  import com.liferay.portal.model.BrowserTracker;
34  import com.liferay.portal.model.Company;
35  import com.liferay.portal.service.BrowserTrackerLocalServiceUtil;
36  import com.liferay.portal.service.CompanyLocalServiceUtil;
37  import com.liferay.portal.util.PortalUtil;
38  import com.liferay.portal.util.PropsValues;
39  import com.liferay.util.Encryptor;
40  import com.liferay.util.servlet.ServletResponseUtil;
41  
42  import java.io.IOException;
43  
44  import java.util.HashMap;
45  import java.util.HashSet;
46  import java.util.Map;
47  import java.util.Set;
48  
49  import javax.servlet.ServletException;
50  import javax.servlet.http.HttpServlet;
51  import javax.servlet.http.HttpServletRequest;
52  import javax.servlet.http.HttpServletResponse;
53  
54  /**
55   * <a href="PollerServlet.java.html"><b><i>View Source</i></b></a>
56   *
57   * @author Brian Wing Shun Chan
58   */
59  public class PollerServlet extends HttpServlet {
60  
61      public void service(
62              HttpServletRequest request, HttpServletResponse response)
63          throws IOException, ServletException {
64  
65          try {
66              String content = getContent(request);
67  
68              if (content == null) {
69                  PortalUtil.sendError(
70                      HttpServletResponse.SC_NOT_FOUND,
71                      new NoSuchLayoutException(), request, response);
72              }
73              else {
74                  response.setContentType(ContentTypes.TEXT_PLAIN_UTF8);
75  
76                  ServletResponseUtil.write(
77                      response, content.getBytes(StringPool.UTF8));
78              }
79          }
80          catch (Exception e) {
81              _log.error(e, e);
82  
83              PortalUtil.sendError(
84                  HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e, request,
85                  response);
86          }
87      }
88  
89      protected String getContent(HttpServletRequest request) throws Exception {
90          String pollerRequestString = getPollerRequestString(request);
91  
92          if (Validator.isNull(pollerRequestString)) {
93              return null;
94          }
95  
96          Map<String, Object>[] pollerRequestChunks =
97              (Map<String, Object>[])JSONFactoryUtil.deserialize(
98                  pollerRequestString);
99  
100         PollerHeader pollerHeader = getPollerHeader(pollerRequestChunks);
101 
102         if (pollerHeader == null) {
103             return null;
104         }
105 
106         boolean receiveRequest = isReceiveRequest(request);
107 
108         JSONArray pollerResponseChunksJSON = null;
109         Set<String> portletIdsWithChunks = null;
110 
111         if (receiveRequest) {
112             pollerResponseChunksJSON = JSONFactoryUtil.createJSONArray();
113             portletIdsWithChunks = new HashSet<String>();
114 
115             boolean suspendPolling = false;
116 
117             if (pollerHeader.isStartPolling()) {
118                 BrowserTrackerLocalServiceUtil.updateBrowserTracker(
119                     pollerHeader.getUserId(), pollerHeader.getBrowserKey());
120             }
121             else {
122                 BrowserTracker browserTracker =
123                     BrowserTrackerLocalServiceUtil.getBrowserTracker(
124                         pollerHeader.getUserId(), pollerHeader.getBrowserKey());
125 
126                 if (browserTracker.getBrowserKey() !=
127                         pollerHeader.getBrowserKey()) {
128 
129                     suspendPolling = true;
130                 }
131             }
132 
133             JSONObject pollerResponseChunkJSON =
134                 JSONFactoryUtil.createJSONObject();
135 
136             pollerResponseChunkJSON.put("userId", pollerHeader.getUserId());
137             pollerResponseChunkJSON.put(
138                 "initialRequest", pollerHeader.isInitialRequest());
139             pollerResponseChunkJSON.put("suspendPolling", suspendPolling);
140 
141             pollerResponseChunksJSON.put(pollerResponseChunkJSON);
142         }
143 
144         PollerRequestManager pollerRequestManager = new PollerRequestManager(
145             pollerResponseChunksJSON, DestinationNames.POLLER,
146             DestinationNames.POLLER_RESPONSE,
147             PropsValues.POLLER_REQUEST_TIMEOUT);
148 
149         for (int i = 1; i < pollerRequestChunks.length; i++) {
150             Map<String, Object> pollerRequestChunk = pollerRequestChunks[i];
151 
152             String portletId = (String)pollerRequestChunk.get("portletId");
153             Map<String, String> parameterMap = getData(pollerRequestChunk);
154             String chunkId = (String)pollerRequestChunk.get("chunkId");
155 
156             try {
157                 PollerRequest pollerRequest = process(
158                     portletIdsWithChunks, pollerHeader, portletId, parameterMap,
159                     chunkId, receiveRequest);
160 
161                 pollerRequestManager.addPollerRequest(pollerRequest);
162             }
163             catch (Exception e) {
164                 _log.error(e, e);
165             }
166         }
167 
168         pollerRequestManager.processRequests();
169 
170         if (!receiveRequest) {
171             return StringPool.BLANK;
172         }
173 
174         pollerRequestManager.clearRequests();
175 
176         for (String portletId : pollerHeader.getPortletIds()) {
177             if (portletIdsWithChunks.contains(portletId)) {
178                 continue;
179             }
180 
181             try {
182                 PollerRequest pollerRequest = process(
183                     portletIdsWithChunks, pollerHeader, portletId,
184                     new HashMap<String, String>(), null, receiveRequest);
185 
186                 pollerRequestManager.addPollerRequest(pollerRequest);
187             }
188             catch (Exception e) {
189                 _log.error(e, e);
190             }
191         }
192 
193         pollerRequestManager.processRequests();
194 
195         pollerResponseChunksJSON = pollerRequestManager.getPollerResponse();
196 
197         return pollerResponseChunksJSON.toString();
198     }
199 
200     protected Map<String, String> getData(
201             Map<String, Object> pollerRequestChunk)
202         throws Exception {
203 
204         Map<String, Object> oldParameterMap =
205             (Map<String, Object>)pollerRequestChunk.get("data");
206 
207         Map<String, String> newParameterMap = new HashMap<String, String>();
208 
209         if (oldParameterMap == null) {
210             return newParameterMap;
211         }
212 
213         for (Map.Entry<String, Object> entry : oldParameterMap.entrySet()) {
214             newParameterMap.put(
215                 entry.getKey(), String.valueOf(entry.getValue()));
216         }
217 
218         return newParameterMap;
219     }
220 
221     protected PollerHeader getPollerHeader(
222             Map<String, Object>[] pollerRequestChunks)
223         throws Exception {
224 
225         if (pollerRequestChunks.length < 1) {
226             return null;
227         }
228 
229         Map<String, Object> pollerRequestChunk = pollerRequestChunks[0];
230 
231         long companyId = GetterUtil.getLong(
232             String.valueOf(pollerRequestChunk.get("companyId")));
233         String userIdString = GetterUtil.getString(
234             String.valueOf(pollerRequestChunk.get("userId")));
235         long browserKey = GetterUtil.getLong(
236             String.valueOf(pollerRequestChunk.get("browserKey")));
237         String[] portletIds = StringUtil.split(
238             String.valueOf(pollerRequestChunk.get("portletIds")));
239         boolean initialRequest = GetterUtil.getBoolean(
240             String.valueOf(pollerRequestChunk.get("initialRequest")));
241         boolean startPolling = GetterUtil.getBoolean(
242             String.valueOf(pollerRequestChunk.get("startPolling")));
243 
244         long userId = getUserId(companyId, userIdString);
245 
246         if (userId == 0) {
247             return null;
248         }
249 
250         return new PollerHeader(
251             companyId, userId, browserKey, portletIds, initialRequest,
252             startPolling);
253     }
254 
255     protected String getPollerRequestString(HttpServletRequest request)
256         throws Exception {
257 
258         String pollerRequestString = ParamUtil.getString(
259             request, "pollerRequest");
260 
261         if (Validator.isNull(pollerRequestString)) {
262             return null;
263         }
264 
265         return StringUtil.replace(
266             pollerRequestString,
267             new String[] {
268                 StringPool.OPEN_CURLY_BRACE,
269                 StringPool.CLOSE_CURLY_BRACE,
270                 _ESCAPED_OPEN_CURLY_BRACE,
271                 _ESCAPED_CLOSE_CURLY_BRACE
272             },
273             new String[] {
274                 _OPEN_HASH_MAP_WRAPPER,
275                 StringPool.DOUBLE_CLOSE_CURLY_BRACE,
276                 StringPool.OPEN_CURLY_BRACE,
277                 StringPool.CLOSE_CURLY_BRACE
278             });
279     }
280 
281     protected long getUserId(long companyId, String userIdString) {
282         long userId = 0;
283 
284         try {
285             Company company = CompanyLocalServiceUtil.getCompany(companyId);
286 
287             userId = GetterUtil.getLong(
288                 Encryptor.decrypt(company.getKeyObj(), userIdString));
289         }
290         catch (Exception e) {
291             _log.error(
292                 "Invalid credentials for company id " + companyId +
293                     " and user id " + userIdString);
294         }
295 
296         return userId;
297     }
298 
299     protected boolean isReceiveRequest(HttpServletRequest request)
300         throws Exception {
301 
302         String path = GetterUtil.getString(request.getPathInfo());
303 
304         if (path.endsWith(_PATH_RECEIVE)) {
305             return true;
306         }
307         else {
308             return false;
309         }
310     }
311 
312     protected PollerRequest process(
313             Set<String> portletIdsWithChunks, PollerHeader pollerHeader,
314             String portletId, Map<String, String> parameterMap, String chunkId,
315             boolean receiveRequest)
316         throws Exception {
317 
318         PollerProcessor pollerProcessor =
319             PollerProcessorUtil.getPollerProcessor(portletId);
320 
321         if (pollerProcessor == null) {
322             _log.error("Poller processor not found for portlet " + portletId);
323 
324             return null;
325         }
326 
327         PollerRequest pollerRequest = new PollerRequest(
328             pollerHeader, portletId, parameterMap, chunkId, receiveRequest);
329 
330         if (receiveRequest) {
331             portletIdsWithChunks.add(portletId);
332         }
333 
334         return pollerRequest;
335     }
336 
337     private static final String _ESCAPED_CLOSE_CURLY_BRACE =
338         "[$CLOSE_CURLY_BRACE$]";
339 
340     private static final String _ESCAPED_OPEN_CURLY_BRACE =
341         "[$OPEN_CURLY_BRACE$]";
342 
343     private static final String _OPEN_HASH_MAP_WRAPPER =
344         "{\"javaClass\":\"java.util.HashMap\",\"map\":{";
345 
346     private static final String _PATH_RECEIVE = "/receive";
347 
348     private static Log _log = LogFactoryUtil.getLog(PollerServlet.class);
349 
350 }