001: /**
002: * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
003: *
004: * Permission is hereby granted, free of charge, to any person obtaining a copy
005: * of this software and associated documentation files (the "Software"), to deal
006: * in the Software without restriction, including without limitation the rights
007: * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
008: * copies of the Software, and to permit persons to whom the Software is
009: * furnished to do so, subject to the following conditions:
010: *
011: * The above copyright notice and this permission notice shall be included in
012: * all copies or substantial portions of the Software.
013: *
014: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
015: * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
016: * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
017: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
018: * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
019: * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
020: * SOFTWARE.
021: */package com.liferay.portal.servlet;
022:
023: import com.liferay.portal.deploy.hot.PluginPackageHotDeployListener;
024: import com.liferay.portal.events.EventsProcessor;
025: import com.liferay.portal.events.StartupAction;
026: import com.liferay.portal.job.Scheduler;
027: import com.liferay.portal.kernel.deploy.hot.HotDeployUtil;
028: import com.liferay.portal.kernel.events.ActionException;
029: import com.liferay.portal.kernel.plugin.PluginPackage;
030: import com.liferay.portal.kernel.pop.MessageListener;
031: import com.liferay.portal.kernel.servlet.HttpHeaders;
032: import com.liferay.portal.kernel.servlet.PortletSessionTracker;
033: import com.liferay.portal.kernel.servlet.ProtectedServletRequest;
034: import com.liferay.portal.kernel.util.ContentTypes;
035: import com.liferay.portal.kernel.util.GetterUtil;
036: import com.liferay.portal.kernel.util.InstancePool;
037: import com.liferay.portal.kernel.util.ParamUtil;
038: import com.liferay.portal.kernel.util.PortalInitableUtil;
039: import com.liferay.portal.kernel.util.ReleaseInfo;
040: import com.liferay.portal.kernel.util.Validator;
041: import com.liferay.portal.lastmodified.LastModifiedAction;
042: import com.liferay.portal.model.ActivityTrackerInterpreter;
043: import com.liferay.portal.model.Company;
044: import com.liferay.portal.model.Portlet;
045: import com.liferay.portal.model.User;
046: import com.liferay.portal.model.impl.ActivityTrackerInterpreterImpl;
047: import com.liferay.portal.pop.POPServerUtil;
048: import com.liferay.portal.security.auth.CompanyThreadLocal;
049: import com.liferay.portal.security.auth.PrincipalThreadLocal;
050: import com.liferay.portal.service.CompanyLocalServiceUtil;
051: import com.liferay.portal.service.PortletLocalServiceUtil;
052: import com.liferay.portal.service.UserLocalServiceUtil;
053: import com.liferay.portal.service.impl.LayoutTemplateLocalUtil;
054: import com.liferay.portal.service.impl.ThemeLocalUtil;
055: import com.liferay.portal.struts.PortletRequestProcessor;
056: import com.liferay.portal.struts.StrutsUtil;
057: import com.liferay.portal.util.ActivityTrackerInterpreterUtil;
058: import com.liferay.portal.util.ContentUtil;
059: import com.liferay.portal.util.InitUtil;
060: import com.liferay.portal.util.PortalInstances;
061: import com.liferay.portal.util.PortalUtil;
062: import com.liferay.portal.util.PropsUtil;
063: import com.liferay.portal.util.PropsValues;
064: import com.liferay.portal.util.ShutdownUtil;
065: import com.liferay.portal.util.WebKeys;
066: import com.liferay.portal.velocity.VelocityContextPool;
067: import com.liferay.portlet.PortletInstanceFactory;
068: import com.liferay.util.CollectionFactory;
069: import com.liferay.util.Http;
070: import com.liferay.util.servlet.EncryptedServletRequest;
071:
072: import java.io.IOException;
073:
074: import java.util.Iterator;
075: import java.util.List;
076: import java.util.Set;
077:
078: import javax.servlet.ServletContext;
079: import javax.servlet.ServletException;
080: import javax.servlet.http.HttpServletRequest;
081: import javax.servlet.http.HttpServletResponse;
082: import javax.servlet.http.HttpSession;
083: import javax.servlet.jsp.PageContext;
084:
085: import org.apache.commons.logging.Log;
086: import org.apache.commons.logging.LogFactory;
087: import org.apache.struts.Globals;
088: import org.apache.struts.action.ActionMapping;
089: import org.apache.struts.action.ActionServlet;
090: import org.apache.struts.config.ModuleConfig;
091: import org.apache.struts.tiles.TilesUtilImpl;
092:
093: import org.dom4j.Document;
094: import org.dom4j.DocumentException;
095: import org.dom4j.Element;
096:
097: import org.quartz.ObjectAlreadyExistsException;
098:
099: /**
100: * <a href="MainServlet.java.html"><b><i>View Source</i></b></a>
101: *
102: * @author Brian Wing Shun Chan
103: * @author Jorge Ferrer
104: * @author Brian Myunghun Kim
105: *
106: */
107: public class MainServlet extends ActionServlet {
108:
109: static {
110: InitUtil.init();
111: }
112:
113: public void init() throws ServletException {
114:
115: // Initialize
116:
117: if (_log.isDebugEnabled()) {
118: _log.debug("Initialize");
119: }
120:
121: super .init();
122:
123: // Process startup events
124:
125: if (_log.isDebugEnabled()) {
126: _log.debug("Process startup events");
127: }
128:
129: try {
130: EventsProcessor.process(new String[] { StartupAction.class
131: .getName() }, true);
132: } catch (RuntimeException re) {
133: ShutdownUtil.shutdown(0);
134:
135: throw new ServletException(re);
136: } catch (ActionException ae) {
137: _log.error(ae, ae);
138: }
139:
140: // Velocity
141:
142: String contextPath = PortalUtil.getPathContext();
143:
144: ServletContext ctx = getServletContext();
145:
146: VelocityContextPool.put(contextPath, ctx);
147:
148: // Initialize plugin package
149:
150: if (_log.isDebugEnabled()) {
151: _log.debug("Initialize plugin package");
152: }
153:
154: PluginPackage pluginPackage = null;
155:
156: try {
157: pluginPackage = PluginPackageHotDeployListener
158: .readPluginPackage(ctx);
159: } catch (Exception e) {
160: _log.error(e, e);
161: }
162:
163: // Initialize portlets
164:
165: if (_log.isDebugEnabled()) {
166: _log.debug("Initialize portlets");
167: }
168:
169: List portlets = null;
170:
171: try {
172: String[] xmls = new String[] {
173: Http.URLtoString(ctx.getResource("/WEB-INF/"
174: + PortalUtil.PORTLET_XML_FILE_NAME_CUSTOM)),
175: Http.URLtoString(ctx
176: .getResource("/WEB-INF/portlet-ext.xml")),
177: Http
178: .URLtoString(ctx
179: .getResource("/WEB-INF/liferay-portlet.xml")),
180: Http
181: .URLtoString(ctx
182: .getResource("/WEB-INF/liferay-portlet-ext.xml")),
183: Http.URLtoString(ctx
184: .getResource("/WEB-INF/web.xml")) };
185:
186: PortletLocalServiceUtil.initEAR(xmls, pluginPackage);
187:
188: portlets = PortletLocalServiceUtil.getPortlets();
189:
190: Iterator itr = portlets.iterator();
191:
192: while (itr.hasNext()) {
193: Portlet portlet = (Portlet) itr.next();
194:
195: PortletInstanceFactory.create(portlet, ctx);
196: }
197: } catch (Exception e) {
198: _log.error(e, e);
199: }
200:
201: // Initialize layout templates
202:
203: if (_log.isDebugEnabled()) {
204: _log.debug("Initialize layout templates");
205: }
206:
207: try {
208: String[] xmls = new String[] {
209: Http
210: .URLtoString(ctx
211: .getResource("/WEB-INF/liferay-layout-templates.xml")),
212: Http
213: .URLtoString(ctx
214: .getResource("/WEB-INF/liferay-layout-templates-ext.xml")) };
215:
216: LayoutTemplateLocalUtil.init(ctx, xmls, pluginPackage);
217: } catch (Exception e) {
218: _log.error(e, e);
219: }
220:
221: // Initialize look and feel
222:
223: if (_log.isDebugEnabled()) {
224: _log.debug("Initialize look and feel");
225: }
226:
227: try {
228: String[] xmls = new String[] {
229: Http
230: .URLtoString(ctx
231: .getResource("/WEB-INF/liferay-look-and-feel.xml")),
232: Http
233: .URLtoString(ctx
234: .getResource("/WEB-INF/liferay-look-and-feel-ext.xml")) };
235:
236: ThemeLocalUtil.init(ctx, null, true, xmls, pluginPackage);
237: } catch (Exception e) {
238: _log.error(e, e);
239: }
240:
241: // Scheduler
242:
243: if (_log.isDebugEnabled()) {
244: _log.debug("Scheduler");
245: }
246:
247: try {
248: if (GetterUtil.getBoolean(PropsUtil
249: .get(PropsUtil.SCHEDULER_ENABLED))) {
250:
251: Iterator itr = portlets.iterator();
252:
253: while (itr.hasNext()) {
254: Portlet portlet = (Portlet) itr.next();
255:
256: String className = portlet.getSchedulerClass();
257:
258: if (portlet.isActive()
259: && Validator.isNotNull(className)) {
260: Scheduler scheduler = (Scheduler) InstancePool
261: .get(className);
262:
263: scheduler.schedule();
264: }
265: }
266: }
267: } catch (ObjectAlreadyExistsException oaee) {
268: } catch (Exception e) {
269: _log.error(e, e);
270: }
271:
272: // Activity tracker interpreter
273:
274: if (_log.isDebugEnabled()) {
275: _log.debug("Activity tracker interpreter");
276: }
277:
278: try {
279: Iterator itr = portlets.iterator();
280:
281: while (itr.hasNext()) {
282: Portlet portlet = (Portlet) itr.next();
283:
284: ActivityTrackerInterpreter activityTrackerInterpreter = portlet
285: .getActivityTrackerInterpreterInstance();
286:
287: if (portlet.isActive()
288: && (activityTrackerInterpreter != null)) {
289:
290: activityTrackerInterpreter = new ActivityTrackerInterpreterImpl(
291: activityTrackerInterpreter);
292:
293: ActivityTrackerInterpreterUtil
294: .addActivityTrackerInterpreter(activityTrackerInterpreter);
295: }
296: }
297: } catch (Exception e) {
298: _log.error(e, e);
299: }
300:
301: // POP message listener
302:
303: if (_log.isDebugEnabled()) {
304: _log.debug("POP message listener");
305: }
306:
307: try {
308: Iterator itr = portlets.iterator();
309:
310: while (itr.hasNext()) {
311: Portlet portlet = (Portlet) itr.next();
312:
313: MessageListener popMessageListener = portlet
314: .getPopMessageListenerInstance();
315:
316: if (portlet.isActive() && (popMessageListener != null)) {
317: POPServerUtil.addListener(popMessageListener);
318: }
319: }
320: } catch (Exception e) {
321: _log.error(e, e);
322: }
323:
324: // Check web settings
325:
326: if (_log.isDebugEnabled()) {
327: _log.debug("Check web settings");
328: }
329:
330: try {
331: String xml = Http.URLtoString(ctx
332: .getResource("/WEB-INF/web.xml"));
333:
334: checkWebSettings(xml);
335: } catch (Exception e) {
336: _log.error(e, e);
337: }
338:
339: // Last modified paths
340:
341: if (_log.isDebugEnabled()) {
342: _log.debug("Last modified paths");
343: }
344:
345: if (_lastModifiedPaths == null) {
346: _lastModifiedPaths = CollectionFactory.getHashSet();
347:
348: String[] pathsArray = PropsUtil
349: .getArray(PropsUtil.LAST_MODIFIED_PATHS);
350:
351: for (int i = 0; i < pathsArray.length; i++) {
352: _lastModifiedPaths.add(pathsArray[i]);
353: }
354: }
355:
356: // Process global startup events
357:
358: if (_log.isDebugEnabled()) {
359: _log.debug("Process global startup events");
360: }
361:
362: try {
363: EventsProcessor.process(PropsUtil
364: .getArray(PropsUtil.GLOBAL_STARTUP_EVENTS), true);
365: } catch (Exception e) {
366: _log.error(e, e);
367: }
368:
369: // Initialize companies
370:
371: String[] webIds = PortalInstances.getWebIds();
372:
373: for (int i = 0; i < webIds.length; i++) {
374: PortalInstances.initCompany(ctx, webIds[i]);
375: }
376:
377: // See LEP-2885. Don't flush hot deploy events until after the portal
378: // has initialized.
379:
380: PortalInitableUtil.flushInitables();
381: HotDeployUtil.flushEvents();
382: }
383:
384: public void callParentService(HttpServletRequest req,
385: HttpServletResponse res) throws IOException,
386: ServletException {
387:
388: super .service(req, res);
389: }
390:
391: public void service(HttpServletRequest req, HttpServletResponse res)
392: throws IOException, ServletException {
393:
394: if (_log.isDebugEnabled()) {
395: _log.debug("Process service request");
396: }
397:
398: if (ShutdownUtil.isShutdown()) {
399: res.setContentType(ContentTypes.TEXT_HTML_UTF8);
400:
401: String html = ContentUtil
402: .get("com/liferay/portal/dependencies/shutdown.html");
403:
404: res.getOutputStream().print(html);
405:
406: return;
407: }
408:
409: HttpSession ses = req.getSession();
410:
411: // Company id
412:
413: long companyId = PortalInstances.getCompanyId(req);
414:
415: //CompanyThreadLocal.setCompanyId(companyId);
416:
417: // CTX
418:
419: ServletContext ctx = getServletContext();
420:
421: req.setAttribute(WebKeys.CTX, ctx);
422:
423: // Struts module config
424:
425: ModuleConfig moduleConfig = getModuleConfig(req);
426:
427: // Last modified check
428:
429: if (PropsValues.LAST_MODIFIED_CHECK) {
430: String path = req.getPathInfo();
431:
432: if ((path != null) && _lastModifiedPaths.contains(path)) {
433: ActionMapping mapping = (ActionMapping) moduleConfig
434: .findActionConfig(path);
435:
436: LastModifiedAction lastModifiedAction = (LastModifiedAction) InstancePool
437: .get(mapping.getType());
438:
439: String lmKey = lastModifiedAction
440: .getLastModifiedKey(req);
441:
442: if (lmKey != null) {
443: long ifModifiedSince = req
444: .getDateHeader(HttpHeaders.IF_MODIFIED_SINCE);
445:
446: if (ifModifiedSince <= 0) {
447: lastModifiedAction.setLastModifiedValue(lmKey,
448: lmKey);
449: } else {
450: String lmValue = lastModifiedAction
451: .getLastModifiedValue(lmKey);
452:
453: if (lmValue != null) {
454: res
455: .setStatus(HttpServletResponse.SC_NOT_MODIFIED);
456:
457: return;
458: } else {
459: lastModifiedAction.setLastModifiedValue(
460: lmKey, lmKey);
461: }
462: }
463: }
464: }
465: }
466:
467: // Portlet session tracker
468:
469: if (ses.getAttribute(WebKeys.PORTLET_SESSION_TRACKER) == null) {
470: ses.setAttribute(WebKeys.PORTLET_SESSION_TRACKER,
471: PortletSessionTracker.getInstance());
472: }
473:
474: // Portlet Request Processor
475:
476: PortletRequestProcessor portletReqProcessor = (PortletRequestProcessor) ctx
477: .getAttribute(WebKeys.PORTLET_STRUTS_PROCESSOR);
478:
479: if (portletReqProcessor == null) {
480: portletReqProcessor = PortletRequestProcessor.getInstance(
481: this , moduleConfig);
482:
483: ctx.setAttribute(WebKeys.PORTLET_STRUTS_PROCESSOR,
484: portletReqProcessor);
485: }
486:
487: // Tiles definitions factory
488:
489: if (ctx.getAttribute(TilesUtilImpl.DEFINITIONS_FACTORY) == null) {
490: ctx.setAttribute(TilesUtilImpl.DEFINITIONS_FACTORY, ctx
491: .getAttribute(TilesUtilImpl.DEFINITIONS_FACTORY));
492: }
493:
494: Object applicationAssociate = ctx
495: .getAttribute(WebKeys.ASSOCIATE_KEY);
496:
497: if (ctx.getAttribute(WebKeys.ASSOCIATE_KEY) == null) {
498: ctx.setAttribute(WebKeys.ASSOCIATE_KEY,
499: applicationAssociate);
500: }
501:
502: // Encrypt request
503:
504: if (ParamUtil.get(req, WebKeys.ENCRYPT, false)) {
505: try {
506: Company company = CompanyLocalServiceUtil
507: .getCompanyById(companyId);
508:
509: req = new EncryptedServletRequest(req, company
510: .getKeyObj());
511: } catch (Exception e) {
512: }
513: }
514:
515: // Current URL
516:
517: PortalUtil.getCurrentURL(req);
518:
519: // Login
520:
521: long userId = PortalUtil.getUserId(req);
522: String remoteUser = req.getRemoteUser();
523:
524: // Is JAAS enabled?
525:
526: if (!PropsValues.PORTAL_JAAS_ENABLE) {
527: String jRemoteUser = (String) ses
528: .getAttribute("j_remoteuser");
529:
530: if (jRemoteUser != null) {
531: remoteUser = jRemoteUser;
532:
533: ses.removeAttribute("j_remoteuser");
534: }
535: }
536:
537: if ((userId > 0) && (remoteUser == null)) {
538: remoteUser = String.valueOf(userId);
539: }
540:
541: // WebSphere will not return the remote user unless you are
542: // authenticated AND accessing a protected path. Other servers will
543: // return the remote user for all threads associated with an
544: // authenticated user. We use ProtectedServletRequest to ensure we get
545: // similar behavior across all servers.
546:
547: req = new ProtectedServletRequest(req, remoteUser);
548:
549: if ((userId > 0) || (remoteUser != null)) {
550:
551: // Set the principal associated with this thread
552:
553: String name = String.valueOf(userId);
554:
555: if (remoteUser != null) {
556: name = remoteUser;
557: }
558:
559: PrincipalThreadLocal.setName(name);
560: }
561:
562: if ((userId <= 0) && (remoteUser != null)) {
563: try {
564:
565: // User id
566:
567: userId = GetterUtil.getLong(remoteUser);
568:
569: // Pre login events
570:
571: EventsProcessor.process(PropsValues.LOGIN_EVENTS_PRE,
572: req, res);
573:
574: // User
575:
576: User user = UserLocalServiceUtil.getUserById(userId);
577:
578: UserLocalServiceUtil.updateLastLogin(userId, req
579: .getRemoteAddr());
580:
581: // User id
582:
583: ses.setAttribute(WebKeys.USER_ID, new Long(userId));
584:
585: // User locale
586:
587: ses.setAttribute(Globals.LOCALE_KEY, user.getLocale());
588:
589: // Post login events
590:
591: EventsProcessor.process(PropsValues.LOGIN_EVENTS_POST,
592: req, res);
593: } catch (Exception e) {
594: _log.error(e, e);
595: }
596: }
597:
598: // Process pre service events
599:
600: try {
601: EventsProcessor.process(
602: PropsValues.SERVLET_SERVICE_EVENTS_PRE, req, res);
603: } catch (Exception e) {
604: _log.error(e, e);
605:
606: req.setAttribute(PageContext.EXCEPTION, e);
607:
608: StrutsUtil.forward(
609: PropsValues.SERVLET_SERVICE_EVENTS_PRE_ERROR_PAGE,
610: ctx, req, res);
611: }
612:
613: try {
614:
615: // Struts service
616:
617: callParentService(req, res);
618: } finally {
619:
620: // Process post service events
621:
622: try {
623: EventsProcessor.process(
624: PropsValues.SERVLET_SERVICE_EVENTS_POST, req,
625: res);
626: } catch (Exception e) {
627: _log.error(e, e);
628: }
629:
630: res.addHeader(_LIFERAY_PORTAL_REQUEST_HEADER, ReleaseInfo
631: .getReleaseInfo());
632:
633: // Clear the company id associated with this thread
634:
635: CompanyThreadLocal.setCompanyId(0);
636:
637: // Clear the principal associated with this thread
638:
639: PrincipalThreadLocal.setName(null);
640: }
641: }
642:
643: public void destroy() {
644: try {
645: Iterator itr = PortletLocalServiceUtil.getPortlets()
646: .iterator();
647:
648: while (itr.hasNext()) {
649: Portlet portlet = (Portlet) itr.next();
650:
651: PortletInstanceFactory.destroy(portlet);
652: }
653: } catch (Exception e) {
654: _log.error(e, e);
655: }
656:
657: long[] companyIds = PortalInstances.getCompanyIds();
658:
659: for (int i = 0; i < companyIds.length; i++) {
660: destroyCompany(companyIds[i]);
661: }
662:
663: try {
664: EventsProcessor.process(PropsUtil
665: .getArray(PropsUtil.GLOBAL_SHUTDOWN_EVENTS), true);
666: } catch (Exception e) {
667: _log.error(e, e);
668: }
669:
670: super .destroy();
671: }
672:
673: protected void checkWebSettings(String xml)
674: throws DocumentException {
675: Document doc = PortalUtil.readDocumentFromXML(xml);
676:
677: Element root = doc.getRootElement();
678:
679: int timeout = PropsValues.SESSION_TIMEOUT;
680:
681: Element sessionConfig = root.element("session-config");
682:
683: if (sessionConfig != null) {
684: String sessionTimeout = sessionConfig
685: .elementText("session-timeout");
686:
687: timeout = GetterUtil.getInteger(sessionTimeout, timeout);
688: }
689:
690: PropsUtil.set(PropsUtil.SESSION_TIMEOUT, String
691: .valueOf(timeout));
692:
693: PropsValues.SESSION_TIMEOUT = timeout;
694: }
695:
696: protected void destroyCompany(long companyId) {
697: if (_log.isDebugEnabled()) {
698: _log.debug("Process shutdown events");
699: }
700:
701: try {
702: EventsProcessor.process(PropsUtil
703: .getArray(PropsUtil.APPLICATION_SHUTDOWN_EVENTS),
704: new String[] { String.valueOf(companyId) });
705: } catch (Exception e) {
706: _log.error(e, e);
707: }
708: }
709:
710: private static final String _LIFERAY_PORTAL_REQUEST_HEADER = "Liferay-Portal";
711:
712: private static Log _log = LogFactory.getLog(MainServlet.class);
713:
714: private Set _lastModifiedPaths;
715:
716: }
|