1
22
23 package com.liferay.portal.servlet;
24
25 import com.liferay.portal.NoSuchLayoutException;
26 import com.liferay.portal.deploy.hot.PluginPackageHotDeployListener;
27 import com.liferay.portal.events.EventsProcessor;
28 import com.liferay.portal.events.StartupAction;
29 import com.liferay.portal.kernel.deploy.hot.HotDeployUtil;
30 import com.liferay.portal.kernel.events.ActionException;
31 import com.liferay.portal.kernel.job.Scheduler;
32 import com.liferay.portal.kernel.plugin.PluginPackage;
33 import com.liferay.portal.kernel.pop.MessageListener;
34 import com.liferay.portal.kernel.servlet.HttpHeaders;
35 import com.liferay.portal.kernel.servlet.PortletSessionTracker;
36 import com.liferay.portal.kernel.servlet.ProtectedServletRequest;
37 import com.liferay.portal.kernel.util.ContentTypes;
38 import com.liferay.portal.kernel.util.GetterUtil;
39 import com.liferay.portal.kernel.util.HttpUtil;
40 import com.liferay.portal.kernel.util.InstancePool;
41 import com.liferay.portal.kernel.util.ParamUtil;
42 import com.liferay.portal.kernel.util.PortalInitableUtil;
43 import com.liferay.portal.kernel.util.ReleaseInfo;
44 import com.liferay.portal.kernel.util.StringPool;
45 import com.liferay.portal.kernel.util.Validator;
46 import com.liferay.portal.lastmodified.LastModifiedAction;
47 import com.liferay.portal.model.Company;
48 import com.liferay.portal.model.Portlet;
49 import com.liferay.portal.model.PortletApp;
50 import com.liferay.portal.model.PortletFilter;
51 import com.liferay.portal.model.PortletURLListener;
52 import com.liferay.portal.model.User;
53 import com.liferay.portal.pop.POPServerUtil;
54 import com.liferay.portal.security.auth.CompanyThreadLocal;
55 import com.liferay.portal.security.auth.PrincipalThreadLocal;
56 import com.liferay.portal.service.CompanyLocalServiceUtil;
57 import com.liferay.portal.service.LayoutTemplateLocalServiceUtil;
58 import com.liferay.portal.service.PortletLocalServiceUtil;
59 import com.liferay.portal.service.ThemeLocalServiceUtil;
60 import com.liferay.portal.service.UserLocalServiceUtil;
61 import com.liferay.portal.struts.PortletRequestProcessor;
62 import com.liferay.portal.struts.StrutsUtil;
63 import com.liferay.portal.util.ContentUtil;
64 import com.liferay.portal.util.DocumentUtil;
65 import com.liferay.portal.util.Portal;
66 import com.liferay.portal.util.PortalInstances;
67 import com.liferay.portal.util.PortalUtil;
68 import com.liferay.portal.util.PropsKeys;
69 import com.liferay.portal.util.PropsUtil;
70 import com.liferay.portal.util.PropsValues;
71 import com.liferay.portal.util.ShutdownUtil;
72 import com.liferay.portal.util.WebKeys;
73 import com.liferay.portal.velocity.VelocityContextPool;
74 import com.liferay.portlet.PortletConfigFactory;
75 import com.liferay.portlet.PortletFilterFactory;
76 import com.liferay.portlet.PortletInstanceFactory;
77 import com.liferay.portlet.PortletURLListenerFactory;
78 import com.liferay.portlet.social.model.SocialActivityInterpreter;
79 import com.liferay.portlet.social.model.SocialRequestInterpreter;
80 import com.liferay.portlet.social.model.impl.SocialActivityInterpreterImpl;
81 import com.liferay.portlet.social.model.impl.SocialRequestInterpreterImpl;
82 import com.liferay.portlet.social.service.SocialActivityInterpreterLocalServiceUtil;
83 import com.liferay.portlet.social.service.SocialRequestInterpreterLocalServiceUtil;
84 import com.liferay.util.servlet.DynamicServletRequest;
85 import com.liferay.util.servlet.EncryptedServletRequest;
86
87 import java.io.IOException;
88
89 import java.util.HashSet;
90 import java.util.Iterator;
91 import java.util.List;
92 import java.util.Set;
93
94 import javax.portlet.PortletConfig;
95 import javax.portlet.PortletContext;
96 import javax.portlet.PortletException;
97
98 import javax.servlet.ServletContext;
99 import javax.servlet.ServletException;
100 import javax.servlet.http.HttpServletRequest;
101 import javax.servlet.http.HttpServletResponse;
102 import javax.servlet.http.HttpSession;
103 import javax.servlet.jsp.PageContext;
104
105 import org.apache.commons.logging.Log;
106 import org.apache.commons.logging.LogFactory;
107 import org.apache.struts.Globals;
108 import org.apache.struts.action.ActionMapping;
109 import org.apache.struts.action.ActionServlet;
110 import org.apache.struts.config.ModuleConfig;
111 import org.apache.struts.tiles.TilesUtilImpl;
112
113 import org.dom4j.Document;
114 import org.dom4j.DocumentException;
115 import org.dom4j.Element;
116
117
125 public class MainServlet extends ActionServlet {
126
127 public void init() throws ServletException {
128
129
131 if (_log.isDebugEnabled()) {
132 _log.debug("Initialize");
133 }
134
135 super.init();
136
137
139 if (_log.isDebugEnabled()) {
140 _log.debug("Process startup events");
141 }
142
143 try {
144 StartupAction startupAction = new StartupAction();
145
146 startupAction.run(null);
147 }
148 catch (RuntimeException re) {
149 ShutdownUtil.shutdown(0);
150
151 throw new ServletException(re);
152 }
153 catch (ActionException ae) {
154 _log.error(ae, ae);
155 }
156
157
159 String contextPath = PortalUtil.getPathContext();
160
161 ServletContext servletContext = getServletContext();
162
163 VelocityContextPool.put(contextPath, servletContext);
164
165
167 if (_log.isDebugEnabled()) {
168 _log.debug("Initialize plugin package");
169 }
170
171 PluginPackage pluginPackage = null;
172
173 try {
174 pluginPackage =
175 PluginPackageHotDeployListener.readPluginPackage(
176 servletContext);
177 }
178 catch (Exception e) {
179 _log.error(e, e);
180 }
181
182
184 if (_log.isDebugEnabled()) {
185 _log.debug("Initialize portlets");
186 }
187
188 List<Portlet> portlets = null;
189
190 try {
191 String[] xmls = new String[] {
192 HttpUtil.URLtoString(servletContext.getResource(
193 "/WEB-INF/" + Portal.PORTLET_XML_FILE_NAME_CUSTOM)),
194 HttpUtil.URLtoString(servletContext.getResource(
195 "/WEB-INF/portlet-ext.xml")),
196 HttpUtil.URLtoString(servletContext.getResource(
197 "/WEB-INF/liferay-portlet.xml")),
198 HttpUtil.URLtoString(servletContext.getResource(
199 "/WEB-INF/liferay-portlet-ext.xml")),
200 HttpUtil.URLtoString(servletContext.getResource(
201 "/WEB-INF/web.xml"))
202 };
203
204 PortletLocalServiceUtil.initEAR(xmls, pluginPackage);
205
206 portlets = PortletLocalServiceUtil.getPortlets();
207
208 for (int i = 0; i < portlets.size(); i++) {
209 Portlet portlet = portlets.get(i);
210
211 if (i == 0) {
212 initPortletApp(portlet, servletContext);
213 }
214
215 PortletInstanceFactory.create(portlet, servletContext);
216 }
217 }
218 catch (Exception e) {
219 _log.error(e, e);
220 }
221
222
224 if (_log.isDebugEnabled()) {
225 _log.debug("Initialize layout templates");
226 }
227
228 try {
229 String[] xmls = new String[] {
230 HttpUtil.URLtoString(servletContext.getResource(
231 "/WEB-INF/liferay-layout-templates.xml")),
232 HttpUtil.URLtoString(servletContext.getResource(
233 "/WEB-INF/liferay-layout-templates-ext.xml"))
234 };
235
236 LayoutTemplateLocalServiceUtil.init(
237 servletContext, xmls, pluginPackage);
238 }
239 catch (Exception e) {
240 _log.error(e, e);
241 }
242
243
245 if (_log.isDebugEnabled()) {
246 _log.debug("Initialize look and feel");
247 }
248
249 try {
250 String[] xmls = new String[] {
251 HttpUtil.URLtoString(servletContext.getResource(
252 "/WEB-INF/liferay-look-and-feel.xml")),
253 HttpUtil.URLtoString(servletContext.getResource(
254 "/WEB-INF/liferay-look-and-feel-ext.xml"))
255 };
256
257 ThemeLocalServiceUtil.init(
258 servletContext, null, true, xmls, pluginPackage);
259 }
260 catch (Exception e) {
261 _log.error(e, e);
262 }
263
264
266 if (_log.isDebugEnabled()) {
267 _log.debug("Scheduler");
268 }
269
270 try {
271 if (PropsValues.SCHEDULER_ENABLED) {
272 for (String className : PropsValues.SCHEDULER_CLASSES) {
273 Scheduler scheduler = (Scheduler)InstancePool.get(
274 className);
275
276 scheduler.schedule();
277 }
278
279 Iterator<Portlet> itr = portlets.iterator();
280
281 while (itr.hasNext()) {
282 Portlet portlet = itr.next();
283
284 String className = portlet.getSchedulerClass();
285
286 if (portlet.isActive() && Validator.isNotNull(className)) {
287 Scheduler scheduler = (Scheduler)InstancePool.get(
288 className);
289
290 scheduler.schedule();
291 }
292 }
293 }
294 }
295 catch (Exception e) {
296 _log.error(e, e);
297 }
298
299
301 if (_log.isDebugEnabled()) {
302 _log.debug("POP message listener");
303 }
304
305 try {
306 Iterator<Portlet> itr = portlets.iterator();
307
308 while (itr.hasNext()) {
309 Portlet portlet = itr.next();
310
311 MessageListener popMessageListener =
312 portlet.getPopMessageListenerInstance();
313
314 if (portlet.isActive() && (popMessageListener != null)) {
315 POPServerUtil.addListener(popMessageListener);
316 }
317 }
318 }
319 catch (Exception e) {
320 _log.error(e, e);
321 }
322
323
325 if (_log.isDebugEnabled()) {
326 _log.debug("Social activity interpreter");
327 }
328
329 try {
330 Iterator<Portlet> itr = portlets.iterator();
331
332 while (itr.hasNext()) {
333 Portlet portlet = itr.next();
334
335 SocialActivityInterpreter socialActivityInterpreter =
336 portlet.getSocialActivityInterpreterInstance();
337
338 if (portlet.isActive() && (socialActivityInterpreter != null)) {
339 socialActivityInterpreter =
340 new SocialActivityInterpreterImpl(
341 portlet.getPortletId(), socialActivityInterpreter);
342
343 SocialActivityInterpreterLocalServiceUtil.
344 addActivityInterpreter(socialActivityInterpreter);
345 }
346 }
347 }
348 catch (Exception e) {
349 _log.error(e, e);
350 }
351
352
354 if (_log.isDebugEnabled()) {
355 _log.debug("Social request interpreter");
356 }
357
358 try {
359 Iterator<Portlet> itr = portlets.iterator();
360
361 while (itr.hasNext()) {
362 Portlet portlet = itr.next();
363
364 SocialRequestInterpreter socialRequestInterpreter =
365 portlet.getSocialRequestInterpreterInstance();
366
367 if (portlet.isActive() && (socialRequestInterpreter != null)) {
368 socialRequestInterpreter = new SocialRequestInterpreterImpl(
369 portlet.getPortletId(), socialRequestInterpreter);
370
371 SocialRequestInterpreterLocalServiceUtil.
372 addRequestInterpreter(socialRequestInterpreter);
373 }
374 }
375 }
376 catch (Exception e) {
377 _log.error(e, e);
378 }
379
380
382 if (_log.isDebugEnabled()) {
383 _log.debug("Check web settings");
384 }
385
386 try {
387 String xml = HttpUtil.URLtoString(
388 servletContext.getResource("/WEB-INF/web.xml"));
389
390 checkWebSettings(xml);
391 }
392 catch (Exception e) {
393 _log.error(e, e);
394 }
395
396
398 if (_log.isDebugEnabled()) {
399 _log.debug("Last modified paths");
400 }
401
402 if (_lastModifiedPaths == null) {
403 _lastModifiedPaths = new HashSet<String>();
404
405 for (String lastModifiedPath : PropsValues.LAST_MODIFIED_PATHS) {
406 _lastModifiedPaths.add(lastModifiedPath);
407 }
408 }
409
410
412 if (_log.isDebugEnabled()) {
413 _log.debug("Process global startup events");
414 }
415
416 try {
417 EventsProcessor.process(
418 PropsKeys.GLOBAL_STARTUP_EVENTS,
419 PropsValues.GLOBAL_STARTUP_EVENTS);
420 }
421 catch (Exception e) {
422 _log.error(e, e);
423 }
424
425
427 String[] webIds = PortalInstances.getWebIds();
428
429 for (int i = 0; i < webIds.length; i++) {
430 PortalInstances.initCompany(servletContext, webIds[i]);
431 }
432
433
436 PortalInitableUtil.flushInitables();
437 HotDeployUtil.flushEvents();
438 }
439
440 public void callParentService(
441 HttpServletRequest request, HttpServletResponse response)
442 throws IOException, ServletException {
443
444 super.service(request, response);
445 }
446
447 public void service(
448 HttpServletRequest request, HttpServletResponse response)
449 throws IOException, ServletException {
450
451 if (_log.isDebugEnabled()) {
452 _log.debug("Process service request");
453 }
454
455 if (ShutdownUtil.isShutdown()) {
456 response.setContentType(ContentTypes.TEXT_HTML_UTF8);
457
458 String html = ContentUtil.get(
459 "com/liferay/portal/dependencies/shutdown.html");
460
461 response.getOutputStream().print(html);
462
463 return;
464 }
465
466 HttpSession session = request.getSession();
467
468
470 long companyId = PortalInstances.getCompanyId(request);
471
472
474
476 PortalUtil.setPortalPort(request);
477
478
480 ServletContext servletContext = getServletContext();
481
482 request.setAttribute(WebKeys.CTX, servletContext);
483
484
486 ModuleConfig moduleConfig = getModuleConfig(request);
487
488
490 if (PropsValues.LAST_MODIFIED_CHECK) {
491 String path = request.getPathInfo();
492
493 if ((path != null) && _lastModifiedPaths.contains(path)) {
494 ActionMapping mapping =
495 (ActionMapping)moduleConfig.findActionConfig(path);
496
497 LastModifiedAction lastModifiedAction =
498 (LastModifiedAction)InstancePool.get(mapping.getType());
499
500 String lmKey = lastModifiedAction.getLastModifiedKey(request);
501
502 if (lmKey != null) {
503 long ifModifiedSince =
504 request.getDateHeader(HttpHeaders.IF_MODIFIED_SINCE);
505
506 if (ifModifiedSince <= 0) {
507 lastModifiedAction.setLastModifiedValue(lmKey, lmKey);
508 }
509 else {
510 String lmValue =
511 lastModifiedAction.getLastModifiedValue(lmKey);
512
513 if (lmValue != null) {
514 response.setStatus(
515 HttpServletResponse.SC_NOT_MODIFIED);
516
517 return;
518 }
519 else {
520 lastModifiedAction.setLastModifiedValue(
521 lmKey, lmKey);
522 }
523 }
524 }
525 }
526 }
527
528
530 if (session.getAttribute(WebKeys.PORTLET_SESSION_TRACKER) == null ) {
531 session.setAttribute(
532 WebKeys.PORTLET_SESSION_TRACKER,
533 PortletSessionTracker.getInstance());
534 }
535
536
538 PortletRequestProcessor portletReqProcessor =
539 (PortletRequestProcessor)servletContext.getAttribute(
540 WebKeys.PORTLET_STRUTS_PROCESSOR);
541
542 if (portletReqProcessor == null) {
543 portletReqProcessor =
544 PortletRequestProcessor.getInstance(this, moduleConfig);
545
546 servletContext.setAttribute(
547 WebKeys.PORTLET_STRUTS_PROCESSOR, portletReqProcessor);
548 }
549
550
552 if (servletContext.getAttribute(
553 TilesUtilImpl.DEFINITIONS_FACTORY) == null) {
554
555 servletContext.setAttribute(
556 TilesUtilImpl.DEFINITIONS_FACTORY,
557 servletContext.getAttribute(TilesUtilImpl.DEFINITIONS_FACTORY));
558 }
559
560 Object applicationAssociate = servletContext.getAttribute(
561 WebKeys.ASSOCIATE_KEY);
562
563 if (servletContext.getAttribute(WebKeys.ASSOCIATE_KEY) == null) {
564 servletContext.setAttribute(
565 WebKeys.ASSOCIATE_KEY, applicationAssociate);
566 }
567
568
570 if (ParamUtil.get(request, WebKeys.ENCRYPT, false)) {
571 try {
572 Company company = CompanyLocalServiceUtil.getCompanyById(
573 companyId);
574
575 request = new EncryptedServletRequest(
576 request, company.getKeyObj());
577 }
578 catch (Exception e) {
579 }
580 }
581
582
584 PortalUtil.getCurrentURL(request);
585
586
588 long userId = PortalUtil.getUserId(request);
589 String remoteUser = request.getRemoteUser();
590
591
593 if (!PropsValues.PORTAL_JAAS_ENABLE) {
594 String jRemoteUser = (String)session.getAttribute("j_remoteuser");
595
596 if (jRemoteUser != null) {
597 remoteUser = jRemoteUser;
598
599 session.removeAttribute("j_remoteuser");
600 }
601 }
602
603 if ((userId > 0) && (remoteUser == null)) {
604 remoteUser = String.valueOf(userId);
605 }
606
607
613 request = new ProtectedServletRequest(request, remoteUser);
614
615 if ((userId > 0) || (remoteUser != null)) {
616
617
619 String name = String.valueOf(userId);
620
621 if (remoteUser != null) {
622 name = remoteUser;
623 }
624
625 PrincipalThreadLocal.setName(name);
626 }
627
628 if ((userId <= 0) && (remoteUser != null)) {
629 try {
630
631
633 userId = GetterUtil.getLong(remoteUser);
634
635
637 EventsProcessor.process(
638 PropsKeys.LOGIN_EVENTS_PRE, PropsValues.LOGIN_EVENTS_PRE,
639 request, response);
640
641
643 User user = UserLocalServiceUtil.getUserById(userId);
644
645 if (PropsValues.USERS_UPDATE_LAST_LOGIN) {
646 UserLocalServiceUtil.updateLastLogin(
647 userId, request.getRemoteAddr());
648 }
649
650
652 session.setAttribute(WebKeys.USER_ID, new Long(userId));
653
654
656 session.setAttribute(Globals.LOCALE_KEY, user.getLocale());
657
658
660 EventsProcessor.process(
661 PropsKeys.LOGIN_EVENTS_POST, PropsValues.LOGIN_EVENTS_POST,
662 request, response);
663 }
664 catch (Exception e) {
665 _log.error(e, e);
666 }
667 }
668
669
671 try {
672 EventsProcessor.process(
673 PropsKeys.SERVLET_SERVICE_EVENTS_PRE,
674 PropsValues.SERVLET_SERVICE_EVENTS_PRE, request, response);
675 }
676 catch (Exception e) {
677 Throwable cause = e.getCause();
678
679 if (cause instanceof NoSuchLayoutException) {
680 DynamicServletRequest dynamicRequest =
681 new DynamicServletRequest(request);
682
683
685 dynamicRequest.setParameter("p_l_id", StringPool.BLANK);
686
687 PortalUtil.sendError(
688 HttpServletResponse.SC_NOT_FOUND,
689 (NoSuchLayoutException)cause, dynamicRequest, response);
690
691 return;
692 }
693
694 _log.error(e, e);
695
696 request.setAttribute(PageContext.EXCEPTION, e);
697
698 StrutsUtil.forward(
699 PropsValues.SERVLET_SERVICE_EVENTS_PRE_ERROR_PAGE,
700 servletContext, request, response);
701
702 return;
703 }
704
705 try {
706
707
709 callParentService(request, response);
710 }
711 finally {
712
713
715 try {
716 EventsProcessor.process(
717 PropsKeys.SERVLET_SERVICE_EVENTS_POST,
718 PropsValues.SERVLET_SERVICE_EVENTS_POST, request, response);
719 }
720 catch (Exception e) {
721 _log.error(e, e);
722 }
723
724 response.addHeader(
725 _LIFERAY_PORTAL_REQUEST_HEADER, ReleaseInfo.getReleaseInfo());
726
727
729 CompanyThreadLocal.setCompanyId(0);
730
731
733 PrincipalThreadLocal.setName(null);
734 }
735 }
736
737 public void destroy() {
738 List<Portlet> portlets = PortletLocalServiceUtil.getPortlets();
739
740
742 if (_log.isDebugEnabled()) {
743 _log.debug("Scheduler");
744 }
745
746 try {
747 if (PropsValues.SCHEDULER_ENABLED) {
748 for (String className : PropsValues.SCHEDULER_CLASSES) {
749 Scheduler scheduler = (Scheduler)InstancePool.get(
750 className);
751
752 scheduler.unschedule();
753 }
754
755 Iterator<Portlet> itr = portlets.iterator();
756
757 while (itr.hasNext()) {
758 Portlet portlet = itr.next();
759
760 String className = portlet.getSchedulerClass();
761
762 if (portlet.isActive() && Validator.isNotNull(className)) {
763 Scheduler scheduler = (Scheduler)InstancePool.get(
764 className);
765
766 scheduler.unschedule();
767 }
768 }
769 }
770 }
771 catch (Exception e) {
772 _log.error(e, e);
773 }
774
775
777 try {
778 Iterator<Portlet> itr = portlets.iterator();
779
780 while (itr.hasNext()) {
781 Portlet portlet = itr.next();
782
783 PortletInstanceFactory.destroy(portlet);
784 }
785 }
786 catch (Exception e) {
787 _log.error(e, e);
788 }
789
790
792 long[] companyIds = PortalInstances.getCompanyIds();
793
794 for (int i = 0; i < companyIds.length; i++) {
795 destroyCompany(companyIds[i]);
796 }
797
798
800 if (_log.isDebugEnabled()) {
801 _log.debug("Process global shutdown events");
802 }
803
804 try {
805 EventsProcessor.process(
806 PropsKeys.GLOBAL_SHUTDOWN_EVENTS,
807 PropsValues.GLOBAL_SHUTDOWN_EVENTS);
808 }
809 catch (Exception e) {
810 _log.error(e, e);
811 }
812
813 super.destroy();
814 }
815
816 protected void checkWebSettings(String xml) throws DocumentException {
817 Document doc = DocumentUtil.readDocumentFromXML(xml);
818
819 Element root = doc.getRootElement();
820
821 int timeout = PropsValues.SESSION_TIMEOUT;
822
823 Element sessionConfig = root.element("session-config");
824
825 if (sessionConfig != null) {
826 String sessionTimeout = sessionConfig.elementText(
827 "session-timeout");
828
829 timeout = GetterUtil.getInteger(sessionTimeout, timeout);
830 }
831
832 PropsUtil.set(PropsKeys.SESSION_TIMEOUT, String.valueOf(timeout));
833
834 PropsValues.SESSION_TIMEOUT = timeout;
835
836 I18nServlet.setLanguageIds(root);
837 }
838
839 protected void destroyCompany(long companyId) {
840 if (_log.isDebugEnabled()) {
841 _log.debug("Process shutdown events");
842 }
843
844 try {
845 EventsProcessor.process(
846 PropsKeys.APPLICATION_SHUTDOWN_EVENTS,
847 PropsValues.APPLICATION_SHUTDOWN_EVENTS,
848 new String[] {String.valueOf(companyId)});
849 }
850 catch (Exception e) {
851 _log.error(e, e);
852 }
853 }
854
855 protected void initPortletApp(
856 Portlet portlet, ServletContext servletContext)
857 throws PortletException {
858
859 PortletApp portletApp = portlet.getPortletApp();
860
861 PortletConfig portletConfig = PortletConfigFactory.create(
862 portlet, servletContext);
863
864 PortletContext portletContext = portletConfig.getPortletContext();
865
866 Set<PortletFilter> portletFilters = portletApp.getPortletFilters();
867
868 for (PortletFilter portletFilter : portletFilters) {
869 PortletFilterFactory.create(portletFilter, portletContext);
870 }
871
872 Set<PortletURLListener> portletURLListeners =
873 portletApp.getPortletURLListeners();
874
875 for (PortletURLListener portletURLListener : portletURLListeners) {
876 PortletURLListenerFactory.create(portletURLListener);
877 }
878 }
879
880 private static final String _LIFERAY_PORTAL_REQUEST_HEADER =
881 "Liferay-Portal";
882
883 private static Log _log = LogFactory.getLog(MainServlet.class);
884
885 private Set<String> _lastModifiedPaths;
886
887 }