001: /*
002: * @author <a href="mailto:novotny@gridsphere.org">Jason Novotny</a>
003: * @version $Id: GridSphereServlet.java 6407 2008-01-16 15:20:21Z wehrens $
004: */
005: package org.gridsphere.servlets;
006:
007: import org.apache.commons.logging.Log;
008: import org.apache.commons.logging.LogFactory;
009: import org.gridsphere.layout.PortletLayoutEngine;
010: import org.gridsphere.layout.PortletPageFactory;
011: import org.gridsphere.portlet.impl.PortletContextImpl;
012: import org.gridsphere.portlet.impl.SportletProperties;
013: import org.gridsphere.portlet.service.PortletServiceException;
014: import org.gridsphere.portlet.service.spi.PortletServiceFactory;
015: import org.gridsphere.portlet.service.spi.impl.descriptor.PortletServiceCollection;
016: import org.gridsphere.portletcontainer.GridSphereEvent;
017: import org.gridsphere.portletcontainer.PortletDispatcherException;
018: import org.gridsphere.portletcontainer.impl.GridSphereEventImpl;
019: import org.gridsphere.portletcontainer.impl.PortletServiceDescriptor;
020: import org.gridsphere.portletcontainer.impl.PortletSessionManager;
021: import org.gridsphere.services.core.filter.PortalFilter;
022: import org.gridsphere.services.core.filter.PortalFilterService;
023: import org.gridsphere.services.core.persistence.PersistenceManagerException;
024: import org.gridsphere.services.core.persistence.PersistenceManagerRdbms;
025: import org.gridsphere.services.core.persistence.PersistenceManagerService;
026: import org.gridsphere.services.core.registry.PortletManagerService;
027: import org.gridsphere.services.core.security.role.PortletRole;
028: import org.gridsphere.services.core.security.role.RoleManagerService;
029: import org.gridsphere.services.core.user.User;
030: import org.gridsphere.services.core.user.UserManagerService;
031: import org.gridsphere.services.core.user.UserPrincipal;
032: import org.gridsphere.services.core.user.impl.UserImpl;
033: import org.hibernate.StaleObjectStateException;
034:
035: import javax.activation.DataHandler;
036: import javax.activation.FileDataSource;
037: import javax.portlet.*;
038: import javax.servlet.*;
039: import javax.servlet.http.*;
040: import java.io.File;
041: import java.io.FileNotFoundException;
042: import java.io.IOException;
043: import java.net.SocketException;
044: import java.security.Principal;
045: import java.util.ArrayList;
046: import java.util.List;
047:
048: /**
049: * The <code>GridSphereServlet</code> is the GridSphere portlet container.
050: * All portlet requests get proccessed by the GridSphereServlet before they
051: * are rendered.
052: */
053: public class GridSphereServlet extends HttpServlet implements
054: ServletContextListener, HttpSessionListener {
055:
056: private Log log = LogFactory.getLog(GridSphereServlet.class);
057:
058: /* GridSphere Portlet Registry Service */
059: private PortletManagerService portletManager = null;
060:
061: /* GridSphere Access Control Service */
062: private RoleManagerService roleService = null;
063:
064: private UserManagerService userManagerService = null;
065:
066: /* GridSphere Portlet layout Engine handles rendering */
067: private PortletLayoutEngine layoutEngine = PortletLayoutEngine
068: .getInstance();
069:
070: private PortletSessionManager sessionManager = PortletSessionManager
071: .getInstance();
072:
073: // private SettingsService settingsService = null;
074:
075: private PortalFilterService portalFilterService = null;
076:
077: private boolean firstDoGet = true;
078:
079: private boolean isTCK = false;
080:
081: /**
082: * Initializes the GridSphere portlet container
083: *
084: * @param config the <code>ServletConfig</code>
085: * @throws ServletException if an error occurs during initialization
086: */
087: public final void init(ServletConfig config)
088: throws ServletException {
089: super .init(config);
090: log.info("in init of GridSphereServlet");
091: String descriptorPath = config.getServletContext().getRealPath(
092: "/WEB-INF/GridSphereServices.xml");
093: // add core gridsphere services to ServiceFactory
094: PortletServiceDescriptor descriptor = null;
095: try {
096: log.debug("loading from: " + descriptorPath);
097: descriptor = new PortletServiceDescriptor(descriptorPath);
098: PortletServiceCollection serviceCollection = descriptor
099: .getServiceCollection();
100: PortletServiceFactory.addServices("gridsphere", config
101: .getServletContext(), serviceCollection, Thread
102: .currentThread().getContextClassLoader());
103: PortletServiceFactory.addSpringServices(config
104: .getServletContext());
105: } catch (PersistenceManagerException e) {
106: //log.error("error unmarshalling " + servicesPath + " using " + servicesMappingPath + " : " + e.getMessage());
107: throw new PortletServiceException("error unmarshalling "
108: + descriptorPath, e);
109: }
110: PortletLayoutEngine layoutEngine = PortletLayoutEngine
111: .getInstance();
112: layoutEngine.init(config.getServletContext());
113: }
114:
115: private void initializeServices() throws PortletServiceException {
116: roleService = (RoleManagerService) PortletServiceFactory
117: .createPortletService(RoleManagerService.class, true);
118: userManagerService = (UserManagerService) PortletServiceFactory
119: .createPortletService(UserManagerService.class, true);
120: portletManager = (PortletManagerService) PortletServiceFactory
121: .createPortletService(PortletManagerService.class, true);
122: portalFilterService = (PortalFilterService) PortletServiceFactory
123: .createPortletService(PortalFilterService.class, true);
124: }
125:
126: public void doGet(HttpServletRequest req, HttpServletResponse res)
127: throws IOException, ServletException {
128:
129: PersistenceManagerService pms = null;
130:
131: pms = (PersistenceManagerService) PortletServiceFactory
132: .createPortletService(PersistenceManagerService.class,
133: true);
134:
135: PersistenceManagerRdbms pm = null;
136: try {
137: log.debug("Starting a database transaction");
138:
139: pm = pms.createGridSphereRdbms();
140: pm.beginTransaction();
141:
142: processRequest(req, res);
143: // Commit and cleanup
144: log.debug("Committing the database transaction");
145:
146: pm.endTransaction();
147: } catch (StaleObjectStateException staleEx) {
148: log
149: .error("This interceptor does not implement optimistic concurrency control!");
150: log
151: .error("Your application will not work until you add compensation actions!");
152: // Rollback, close everything, possibly compensate for any permanent changes
153: // during the conversation, and finally restart business conversation. Maybe
154: // give the user of the application a chance to merge some of his work with
155: // fresh data... what you do here depends on your applications design.
156: //throw staleEx;
157: } catch (Throwable ex) {
158: ex.printStackTrace();
159: pm.endTransaction();
160: try {
161: pm.rollbackTransaction();
162: } catch (Throwable rbEx) {
163: log
164: .error(
165: "Could not rollback transaction after exception!",
166: rbEx);
167: }
168: // Let others handle it... maybe another interceptor for exceptions?
169: //throw new ServletException(ex);
170: }
171: }
172:
173: /**
174: * Processes GridSphere portal framework requests
175: *
176: * @param req the <code>HttpServletRequest</code>
177: * @param res the <code>HttpServletResponse</code>
178: * @throws IOException if an I/O error occurs
179: * @throws ServletException if a servlet error occurs
180: */
181: public void processRequest(HttpServletRequest req,
182: HttpServletResponse res) throws IOException,
183: ServletException {
184:
185: if (firstDoGet) {
186: initializeServices();
187: updateDatabase();
188: firstDoGet = false;
189: }
190:
191: long startTime = System.currentTimeMillis();
192:
193: PortletContext ctx = new PortletContextImpl(getServletContext());
194: GridSphereEvent event = new GridSphereEventImpl(ctx, req, res);
195:
196: // check to see if user has been authorized by means of container managed authorization
197: checkWebContainerAuthorization(event);
198:
199: List<PortalFilter> portalFilters = portalFilterService
200: .getPortalFilters();
201: for (PortalFilter filter : portalFilters) {
202: filter.doBeforeEveryRequest(req, res);
203: }
204:
205: // Used for TCK tests
206:
207: if (isTCK) {
208: req.setAttribute(SportletProperties.LAYOUT_PAGE,
209: PortletPageFactory.TCK_PAGE);
210: setTCKUser(req);
211: } else {
212: setUserAndRoles(event);
213: }
214:
215: // Handle user login and logout
216: if (event.hasAction()) {
217: String actionName = event.getAction().getName();
218: if (actionName.equals(SportletProperties.LOGOUT)) {
219: logout(event);
220: long endTime = System.currentTimeMillis();
221: System.err.println("Page render time = "
222: + (endTime - startTime) + " (ms) request= "
223: + req.getQueryString());
224: return;
225: }
226: }
227:
228: layoutEngine.actionPerformed(event);
229:
230: //GPF-457 fix
231: if (null != req
232: .getAttribute(SportletProperties.PORTAL_FILTER_EVENT)) {
233: //only doAfterLogin is checked since logout request doesn't reach this code
234: if (SportletProperties.PORTAL_FILTER_EVENT_AFTER_LOGIN
235: .equals(req
236: .getAttribute(SportletProperties.PORTAL_FILTER_EVENT))) {
237: for (PortalFilter portalFilter : portalFilters) {
238: PortalFilter filter = (PortalFilter) portalFilter;
239: filter.doAfterLogin(req, res);
240: }
241: }
242: }
243:
244: // perform a redirect-after-POST!
245: if (event.hasAction()
246: && req.getMethod().toUpperCase().equals("POST")) {
247: String requestURL = (String) req
248: .getAttribute(SportletProperties.PORTAL_REDIRECT_PATH);
249: if (req.getParameter("ajax") == null) {
250: log.debug("redirect after POST to: " + requestURL);
251: res.sendRedirect(requestURL);
252: return;
253: }
254: }
255:
256: // is this a file download operation?
257: if (isDownload(req)) {
258: try {
259: downloadFile(req, res);
260: return;
261: } catch (PortletException e) {
262: log.error("Unable to download file!", e);
263: req.setAttribute(
264: SportletProperties.FILE_DOWNLOAD_ERROR, e);
265: }
266: }
267:
268: // Used for TCK tests
269: if (isTCK) {
270: setTCKUser(req);
271: } else {
272: setUserAndRoles(event);
273: }
274:
275: layoutEngine.service(event);
276:
277: for (PortalFilter portalFilter : portalFilters) {
278: PortalFilter filter = (PortalFilter) portalFilter;
279: filter.doAfterEveryRequest(req, res);
280: }
281:
282: //log.debug("Portlet service factory stats");
283: //factory.logStatistics();
284: long endTime = System.currentTimeMillis();
285: System.err.println("Page render time = "
286: + (endTime - startTime) + " (ms) request= "
287: + req.getQueryString());
288: sessionManager.dumpSessions();
289: System.err.println("after dump");
290:
291: //event.getRenderResponse().createRenderURL();
292: }
293:
294: /**
295: * Method to set the response headers to perform file downloads to a browser
296: *
297: * @param req the HttpServletRequest
298: * @param res the HttpServletResponse
299: * @throws PortletException if a portlet exception occurs
300: * @throws IOException if an IO error occurs
301: */
302: public void downloadFile(HttpServletRequest req,
303: HttpServletResponse res) throws PortletException,
304: IOException {
305:
306: String fileName = (String) req
307: .getAttribute(SportletProperties.FILE_DOWNLOAD_NAME);
308: if (fileName == null)
309: return;
310: String path = (String) req
311: .getAttribute(SportletProperties.FILE_DOWNLOAD_PATH);
312: Boolean deleteFile = (Boolean) req
313: .getAttribute(SportletProperties.FILE_DELETE);
314: File file = (File) req
315: .getAttribute(SportletProperties.FILE_DOWNLOAD_BINARY);
316:
317: req.removeAttribute(SportletProperties.FILE_DOWNLOAD_NAME);
318: req.removeAttribute(SportletProperties.FILE_DOWNLOAD_PATH);
319: req.removeAttribute(SportletProperties.FILE_DELETE);
320: req.removeAttribute(SportletProperties.FILE_DOWNLOAD_BINARY);
321:
322: try {
323: if (file == null) {
324: file = new File(path + fileName);
325: }
326: if (deleteFile == null)
327: deleteFile = Boolean.FALSE;
328: log.debug("in downloadFile");
329: log.debug("filename: " + fileName + " filepath= " + path);
330: FileDataSource fds = new FileDataSource(file);
331: log.debug("filename: " + fileName + " filepath= " + path
332: + " content type=" + fds.getContentType());
333: res.setContentType(fds.getContentType());
334: res.setHeader("Content-Disposition",
335: "attachment; filename=" + fileName);
336: res.setHeader("Content-Length", String.valueOf(file
337: .length()));
338: DataHandler handler = new DataHandler(fds);
339: handler.writeTo(res.getOutputStream());
340: if (deleteFile.booleanValue()) {
341: file.delete();
342: }
343: } catch (FileNotFoundException e) {
344: throw new PortletException("Unable to find file!", e);
345: } catch (SecurityException e) {
346: // this gets thrown if a security policy applies to the file. see java.io.File for details.
347: throw new PortletException("A security error occurred!", e);
348: } catch (SocketException e) {
349: throw new PortletException("A socket error occurred!", e);
350: }
351: }
352:
353: public boolean isDownload(HttpServletRequest req) {
354: return (req.getAttribute(SportletProperties.FILE_DOWNLOAD_NAME) != null);
355: }
356:
357: public void setTCKUser(HttpServletRequest req) {
358: log.info("Setting a TCK user");
359: UserImpl u = new UserImpl();
360: u.setUserName("tckuser");
361: u.setUserID("tckuser");
362: u.setID("500");
363: req.setAttribute(SportletProperties.PORTLET_USER, u);
364: req.setAttribute(SportletProperties.PORTLET_ROLE,
365: new ArrayList());
366: isTCK = true;
367: }
368:
369: public void setUserAndRoles(GridSphereEvent event) {
370: // Retrieve user if there is one
371: HttpServletRequest req = event.getHttpServletRequest();
372: HttpSession session = req.getSession(true);
373: User user = null;
374: String uid = (String) session
375: .getAttribute(SportletProperties.PORTLET_USER);
376: if (uid != null) {
377: user = userManagerService.getUser(uid);
378: }
379: List<String> roles = new ArrayList<String>();
380: if (user != null) {
381: UserPrincipal userPrincipal = new UserPrincipal(user
382: .getUserName());
383: req.setAttribute(SportletProperties.PORTLET_USER_PRINCIPAL,
384: userPrincipal);
385: List<PortletRole> proles = roleService
386: .getRolesForUser(user);
387: for (PortletRole role : proles) {
388: roles.add(role.getName());
389: }
390: }
391:
392: // set user, role and groups in request
393: req.setAttribute(SportletProperties.PORTLET_USER, user);
394: req.setAttribute(SportletProperties.PORTLET_ROLE, roles);
395: }
396:
397: // Dmitry Gavrilov (2005-03-17)
398: // FIX for web container authorization
399: private void checkWebContainerAuthorization(GridSphereEvent event) {
400: PortletRequest request = event.getActionRequest();
401: PortletSession session = request.getPortletSession();
402: if (session.getAttribute(SportletProperties.PORTLET_USER) != null)
403: return;
404: if (!(event.hasAction() && event.getAction().getName().equals(
405: SportletProperties.LOGOUT))) {
406: Principal principal = request.getUserPrincipal();
407: if (principal != null) {
408: // fix for OC4J. it must work in Tomcat also
409: int indeDelimeter = principal.getName()
410: .lastIndexOf('/');
411: indeDelimeter = (indeDelimeter > 0) ? (indeDelimeter + 1)
412: : 0;
413: String login = principal.getName().substring(
414: indeDelimeter);
415: User user = userManagerService.getUserByUserName(login);
416: if (user != null) {
417: request.setAttribute(
418: SportletProperties.PORTLET_USER, user);
419: session.setAttribute(
420: SportletProperties.PORTLET_USER, user
421: .getID(),
422: PortletSession.APPLICATION_SCOPE);
423: request
424: .setAttribute(
425: SportletProperties.PORTAL_FILTER_EVENT,
426: SportletProperties.PORTAL_FILTER_EVENT_AFTER_LOGIN);
427: }
428: }
429: }
430: }
431:
432: /**
433: * Handles logout requests
434: *
435: * @param event a <code>GridSphereEvent</code>
436: */
437: protected void logout(GridSphereEvent event) {
438: log.debug("in logout of GridSphere Servlet");
439: PortletRequest req = event.getActionRequest();
440: RenderResponse res = event.getRenderResponse();
441: //removeUserCookie(event);
442:
443: req.removeAttribute(SportletProperties.PORTLET_USER);
444: req.removeAttribute(SportletProperties.PORTLET_USER_PRINCIPAL);
445:
446: try {
447: portletManager.logoutAllPortletWebApplications(event
448: .getHttpServletRequest(), event
449: .getHttpServletResponse());
450: } catch (PortletDispatcherException e) {
451: log.error("Failed to logout portlets!", e);
452: }
453:
454: List<PortalFilter> portalFilters = portalFilterService
455: .getPortalFilters();
456: for (PortalFilter filter : portalFilters) {
457: filter.doAfterLogout(event.getHttpServletRequest(), event
458: .getHttpServletResponse());
459: }
460:
461: try {
462: String url = res.createRenderURL().toString();
463: log.error("Post logout redirect to " + url);
464: event.getHttpServletResponse().sendRedirect(url);
465: } catch (IOException e) {
466: log.error("Unable to do a redirect!", e);
467: }
468: }
469:
470: /**
471: * @see #doGet
472: */
473: public final void doPost(HttpServletRequest req,
474: HttpServletResponse res) throws IOException,
475: ServletException {
476: doGet(req, res);
477: }
478:
479: /**
480: * Return the servlet info.
481: *
482: * @return a string with the servlet information.
483: */
484: public final String getServletInfo() {
485: return "GridSphere Servlet";
486: }
487:
488: /**
489: * Shuts down the GridSphere portlet container
490: */
491: public final void destroy() {
492: log.debug("in destroy: Shutting down services");
493: // Shutdown services
494: PortletServiceFactory.shutdownServices();
495: System.gc();
496: }
497:
498: /**
499: * Record the fact that a servlet context attribute was added.
500: *
501: * @param event The session attribute event
502: */
503: public void attributeAdded(HttpSessionBindingEvent event) {
504: try {
505: log.debug("attributeAdded('" + event.getSession().getId()
506: + "', '" + event.getName() + "', '"
507: + event.getValue() + "')");
508: } catch (IllegalStateException e) {
509: // do nothing
510: }
511: }
512:
513: /**
514: * Record the fact that a servlet context attribute was removed.
515: *
516: * @param event The session attribute event
517: */
518: public void attributeRemoved(HttpSessionBindingEvent event) {
519: try {
520: log.debug("attributeRemoved('" + event.getSession().getId()
521: + "', '" + event.getName() + "', '"
522: + event.getValue() + "')");
523: } catch (IllegalStateException e) {
524: // do nothing
525: }
526:
527: }
528:
529: /**
530: * Record the fact that a servlet context attribute was replaced.
531: *
532: * @param event The session attribute event
533: */
534: public void attributeReplaced(HttpSessionBindingEvent event) {
535: try {
536: log.debug("attributeReplaced('"
537: + event.getSession().getId() + "', '"
538: + event.getName() + "', '" + event.getValue()
539: + "')");
540: } catch (IllegalStateException e) {
541: // do nothing
542: }
543:
544: }
545:
546: /**
547: * Record the fact that this ui application has been destroyed.
548: *
549: * @param event The servlet context event
550: */
551: public void contextDestroyed(ServletContextEvent event) {
552: ServletContext ctx = event.getServletContext();
553: log.debug("contextDestroyed()");
554: log.debug("contextName: " + ctx.getServletContextName());
555: log.debug("context path: " + ctx.getRealPath(""));
556: }
557:
558: /**
559: * Record the fact that this ui application has been initialized.
560: *
561: * @param event The servlet context event
562: */
563: public void contextInitialized(ServletContextEvent event) {
564: System.err
565: .println("in contextInitialized of GridSphereServlet");
566: ServletContext ctx = event.getServletContext();
567: log.info("contextName: " + ctx.getServletContextName());
568: log.debug("context path: " + ctx.getRealPath(""));
569:
570: }
571:
572: /**
573: * Record the fact that a session has been created.
574: *
575: * @param event The session event
576: */
577: public void sessionCreated(HttpSessionEvent event) {
578: System.err.println("sessionCreated('"
579: + event.getSession().getId() + "')");
580: sessionManager.sessionCreated(event);
581: }
582:
583: /**
584: * Record the fact that a session has been destroyed.
585: *
586: * @param event The session event
587: */
588: public void sessionDestroyed(HttpSessionEvent event) {
589: sessionManager.sessionDestroyed(event);
590: System.err.println("sessionDestroyed('"
591: + event.getSession().getId() + "')");
592: }
593:
594: public void updateDatabase() {
595: // loop thru users make sure first and last name are created from full name
596: List<User> users = userManagerService.getUsers();
597: for (User user : users) {
598: if (user.getFirstName().equals("")
599: && user.getLastName().equals("")) {
600: String full = user.getFullName();
601: int idx = full.lastIndexOf(" ");
602: if (idx > 0) {
603: user.setFirstName(full.substring(0, idx));
604: user.setLastName(full.substring(idx + 1));
605: } else {
606: user.setFirstName(full);
607: }
608: Integer numLogins = user.getNumLogins();
609: if (numLogins == null)
610: numLogins = 0;
611: user.setNumLogins(numLogins++);
612: userManagerService.saveUser(user);
613: }
614: }
615: }
616: }
|