/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/portal/branches/sakai-2.8.1/portal-impl/impl/src/java/org/sakaiproject/portal/charon/SkinnableCharonPortal.java $ * $Id: SkinnableCharonPortal.java 93969 2011-06-22 23:02:32Z ottenhoff@longsight.com $ *********************************************************************************** * * Copyright (c) 2005, 2006, 2007, 2008 The Sakai Foundation * * Licensed under the Educational Community License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.osedu.org/licenses/ECL-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * **********************************************************************************/ package org.sakaiproject.portal.charon; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import net.sourceforge.wurfl.core.Device; import net.sourceforge.wurfl.core.DeviceNotDefinedException; import net.sourceforge.wurfl.core.WURFLHolder; import net.sourceforge.wurfl.core.WURFLManager; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.authz.cover.SecurityService; import org.sakaiproject.component.cover.ServerConfigurationService; import org.sakaiproject.entity.api.ResourceProperties; import org.sakaiproject.exception.IdUnusedException; import org.sakaiproject.exception.PermissionException; import org.sakaiproject.portal.api.Editor; import org.sakaiproject.portal.api.PageFilter; import org.sakaiproject.portal.api.Portal; import org.sakaiproject.portal.api.PortalHandler; import org.sakaiproject.portal.api.PortalRenderContext; import org.sakaiproject.portal.api.PortalRenderEngine; import org.sakaiproject.portal.api.PortalService; import org.sakaiproject.portal.api.PortalSiteHelper; import org.sakaiproject.portal.api.SiteNeighbourhoodService; import org.sakaiproject.portal.api.SiteView; import org.sakaiproject.portal.api.StoredState; import org.sakaiproject.portal.charon.handlers.AtomHandler; import org.sakaiproject.portal.charon.handlers.DirectToolHandler; import org.sakaiproject.portal.charon.handlers.ErrorDoneHandler; import org.sakaiproject.portal.charon.handlers.ErrorReportHandler; import org.sakaiproject.portal.charon.handlers.GalleryHandler; import org.sakaiproject.portal.charon.handlers.GalleryResetHandler; import org.sakaiproject.portal.charon.handlers.HelpHandler; import org.sakaiproject.portal.charon.handlers.LoginHandler; import org.sakaiproject.portal.charon.handlers.LogoutHandler; import org.sakaiproject.portal.charon.handlers.NavLoginHandler; import org.sakaiproject.portal.charon.handlers.OpmlHandler; import org.sakaiproject.portal.charon.handlers.PDAHandler; import org.sakaiproject.portal.charon.handlers.PageHandler; import org.sakaiproject.portal.charon.handlers.PresenceHandler; import org.sakaiproject.portal.charon.handlers.ReLoginHandler; import org.sakaiproject.portal.charon.handlers.RoleSwitchHandler; import org.sakaiproject.portal.charon.handlers.RoleSwitchOutHandler; import org.sakaiproject.portal.charon.handlers.RssHandler; import org.sakaiproject.portal.charon.handlers.SiteHandler; import org.sakaiproject.portal.charon.handlers.SiteResetHandler; import org.sakaiproject.portal.charon.handlers.StaticScriptsHandler; import org.sakaiproject.portal.charon.handlers.StaticStylesHandler; import org.sakaiproject.portal.charon.handlers.TimeoutDialogHandler; import org.sakaiproject.portal.charon.handlers.ToolHandler; import org.sakaiproject.portal.charon.handlers.ToolResetHandler; import org.sakaiproject.portal.charon.handlers.WorksiteHandler; import org.sakaiproject.portal.charon.handlers.WorksiteResetHandler; import org.sakaiproject.portal.charon.handlers.XLoginHandler; import org.sakaiproject.portal.charon.site.PortalSiteHelperImpl; import org.sakaiproject.portal.render.api.RenderResult; import org.sakaiproject.portal.render.cover.ToolRenderService; import org.sakaiproject.portal.util.BrowserDetector; import org.sakaiproject.portal.util.ErrorReporter; import org.sakaiproject.portal.util.ToolURLManagerImpl; import org.sakaiproject.portal.util.URLUtils; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.SitePage; import org.sakaiproject.site.api.ToolConfiguration; import org.sakaiproject.site.cover.SiteService; import org.sakaiproject.thread_local.cover.ThreadLocalManager; import org.sakaiproject.tool.api.ActiveTool; import org.sakaiproject.tool.api.Placement; import org.sakaiproject.tool.api.Session; import org.sakaiproject.tool.api.Tool; import org.sakaiproject.tool.api.ToolException; import org.sakaiproject.tool.api.ToolSession; import org.sakaiproject.tool.api.ToolURL; import org.sakaiproject.tool.cover.ActiveToolManager; import org.sakaiproject.tool.cover.SessionManager; import org.sakaiproject.tool.cover.ToolManager; import org.sakaiproject.user.api.User; import org.sakaiproject.user.api.UserNotDefinedException; import org.sakaiproject.user.cover.UserDirectoryService; import org.sakaiproject.util.BasicAuth; import org.sakaiproject.util.EditorConfiguration; import org.sakaiproject.util.ResourceLoader; import org.apache.commons.lang.StringUtils; import org.sakaiproject.util.Validator; import org.sakaiproject.util.Web; /** * <p/> Charon is the Sakai Site based portal. * </p> * * @since Sakai 2.4 * @version $Rev: 93969 $ * */ @SuppressWarnings("deprecation") public class SkinnableCharonPortal extends HttpServlet implements Portal { /** * */ private static final long serialVersionUID = 2645929710236293089L; /** * Our log (commons). */ private static Log M_log = LogFactory.getLog(SkinnableCharonPortal.class); /** * messages. */ private static ResourceLoader rloader = new ResourceLoader("sitenav"); /** * Parameter value to indicate to look up a tool ID within a site */ protected static final String PARAM_SAKAI_SITE = "sakai.site"; private BasicAuth basicAuth = null; private boolean enableDirect = false; private PortalService portalService; private static final String PADDING = "               "; private static final String INCLUDE_BOTTOM = "include-bottom"; private static final String INCLUDE_LOGIN = "include-login"; private static final String INCLUDE_TITLE = "include-title"; private PortalSiteHelper siteHelper = null; // private HashMap<String, PortalHandler> handlerMap = new HashMap<String, // PortalHandler>(); private GalleryHandler galleryHandler; private String gatewaySiteUrl; private WorksiteHandler worksiteHandler; private SiteHandler siteHandler; private String portalContext; private String PROP_PARENT_ID = SiteService.PROP_PARENT_ID; // 2.3 back port // public String String PROP_PARENT_ID = "sakai:parent-id"; private String PROP_SHOW_SUBSITES = SiteService.PROP_SHOW_SUBSITES ; private final String PROP_PDA_HTML_INCLUDE = "sakai:pdaHtmlInclude"; // 2.3 back port // public String PROP_SHOW_SUBSITES = "sakai:show-subsites"; // http://wurfl.sourceforge.net/ private boolean wurflLoaded = false; private WURFLHolder wurflHolder = null; private WURFLManager wurfl = null; /* public CapabilityMatrix cm = null; public UAManager uam = null; */ private boolean forceContainer = false; private String handlerPrefix; private PageFilter pageFilter = new PageFilter() { public List filter(List newPages, Site site) { return newPages; } public List<Map> filterPlacements(List<Map> l, Site site) { return l; } }; // define string that identifies this as the logged in users' my workspace private String myWorkspaceSiteId = "~"; public String getPortalContext() { return portalContext; } /** * Shutdown the servlet. */ public void destroy() { M_log.info("destroy()"); portalService.removePortal(this); super.destroy(); } public void doError(HttpServletRequest req, HttpServletResponse res, Session session, int mode) throws ToolException, IOException { if (ThreadLocalManager.get(ATTR_ERROR) == null) { ThreadLocalManager.set(ATTR_ERROR, ATTR_ERROR); // send to the error site switch (mode) { case ERROR_SITE: { siteHandler.doSite(req, res, session, "!error", null, req .getContextPath() + req.getServletPath()); break; } case ERROR_GALLERY: { galleryHandler.doGallery(req, res, session, "!error", null, req .getContextPath() + req.getServletPath()); break; } case ERROR_WORKSITE: { worksiteHandler.doWorksite(req, res, session, "!error", null, req .getContextPath() + req.getServletPath()); break; } } return; } // error and we cannot use the error site... // form a context sensitive title String title = ServerConfigurationService.getString("ui.service") + " : Portal"; // start the response PortalRenderContext rcontext = startPageContext("", title, null, req); showSession(rcontext, true); showSnoop(rcontext, true, getServletConfig(), req); sendResponse(rcontext, res, "error", null); } private void showSnoop(PortalRenderContext rcontext, boolean b, ServletConfig servletConfig, HttpServletRequest req) { Enumeration e = null; rcontext.put("snoopRequest", req.toString()); if (servletConfig != null) { Map<String, Object> m = new HashMap<String, Object>(); e = servletConfig.getInitParameterNames(); if (e != null) { boolean first = true; while (e.hasMoreElements()) { String param = (String) e.nextElement(); m.put(param, servletConfig.getInitParameter(param)); } } rcontext.put("snoopServletConfigParams", m); } rcontext.put("snoopRequest", req); e = req.getHeaderNames(); if (e.hasMoreElements()) { Map<String, Object> m = new HashMap<String, Object>(); while (e.hasMoreElements()) { String name = (String) e.nextElement(); m.put(name, req.getHeader(name)); } rcontext.put("snoopRequestHeaders", m); } e = req.getParameterNames(); if (e.hasMoreElements()) { Map<String, Object> m = new HashMap<String, Object>(); while (e.hasMoreElements()) { String name = (String) e.nextElement(); m.put(name, req.getParameter(name)); } rcontext.put("snoopRequestParamsSingle", m); } e = req.getParameterNames(); if (e.hasMoreElements()) { Map<String, Object> m = new HashMap<String, Object>(); while (e.hasMoreElements()) { String name = (String) e.nextElement(); String[] vals = (String[]) req.getParameterValues(name); StringBuilder sb = new StringBuilder(); if (vals != null) { sb.append(vals[0]); for (int i = 1; i < vals.length; i++) sb.append(" ").append(vals[i]); } m.put(name, sb.toString()); } rcontext.put("snoopRequestParamsMulti", m); } e = req.getAttributeNames(); if (e.hasMoreElements()) { Map<String, Object> m = new HashMap<String, Object>(); while (e.hasMoreElements()) { String name = (String) e.nextElement(); m.put(name, req.getAttribute(name)); } rcontext.put("snoopRequestAttr", m); } } protected void doThrowableError(HttpServletRequest req, HttpServletResponse res, Throwable t) { ErrorReporter err = new ErrorReporter(); err.report(req, res, t); } /* * * * Include the children of a site */ // TODO: Extract to a provider public void includeSubSites(PortalRenderContext rcontext, HttpServletRequest req, Session session, String siteId, String toolContextPath, String prefix, boolean resetTools) // throws ToolException, IOException { if ( siteId == null || rcontext == null ) return; // Check the setting as to whether we are to do this String pref = ServerConfigurationService.getString("portal.includesubsites"); if ( "never".equals(pref) ) return; Site site = null; try { site = siteHelper.getSiteVisit(siteId); } catch (Exception e) { return; } if ( site == null ) return; ResourceProperties rp = site.getProperties(); String showSub = rp.getProperty(PROP_SHOW_SUBSITES); // System.out.println("Checking subsite pref:"+site.getTitle()+" pref="+pref+" show="+showSub); if ( "false".equals(showSub) ) return; if ( "false".equals(pref) ) { if ( ! "true".equals(showSub) ) return; } SiteView siteView = siteHelper.getSitesView(SiteView.View.SUB_SITES_VIEW,req, session, siteId); if ( siteView.isEmpty() ) return; siteView.setPrefix(prefix); siteView.setToolContextPath(toolContextPath); siteView.setResetTools(resetTools); if( !siteView.isEmpty() ) { rcontext.put("subSites", siteView.getRenderContextObject()); } } /* * Produce a portlet like view with the navigation all at the top with * implicit reset */ public PortalRenderContext includePortal(HttpServletRequest req, HttpServletResponse res, Session session, String siteId, String toolId, String toolContextPath, String prefix, boolean doPages, boolean resetTools, boolean includeSummary, boolean expandSite) throws ToolException, IOException { String errorMessage = null; String sitePdaHtmlInclude = null; // find the site, for visiting Site site = null; try { site = siteHelper.getSiteVisit(siteId); sitePdaHtmlInclude = site.getProperties().getProperty(PROP_PDA_HTML_INCLUDE); } catch (IdUnusedException e) { errorMessage = "Unable to find site: " + siteId; siteId = null; toolId = null; } catch (PermissionException e) { if (session.getUserId() == null) { errorMessage = "No permission for anonymous user to view site: " + siteId; } else { errorMessage = "No permission to view site: " + siteId; } siteId = null; toolId = null; // Tool needs the site and needs it to be visitable } // Get the Tool Placement ToolConfiguration placement = null; if (site != null && toolId != null) { placement = SiteService.findTool(toolId); if (placement == null) { errorMessage = "Unable to find tool placement " + toolId; toolId = null; } boolean thisTool = siteHelper.allowTool(site, placement); if (!thisTool) { errorMessage = "No permission to view tool placement " + toolId; toolId = null; placement = null; } } // form a context sensitive title String title = ServerConfigurationService.getString("ui.service"); if (site != null) { title = title + ":" + site.getTitle(); if (placement != null) title = title + " : " + placement.getTitle(); } // start the response String siteType = null; String siteSkin = null; if (site != null) { siteType = calcSiteType(siteId); siteSkin = site.getSkin(); } PortalRenderContext rcontext = startPageContext(siteType, title, siteSkin, req); if (sitePdaHtmlInclude != null) rcontext.put("sitePdaHtmlInclude", sitePdaHtmlInclude); // Make the top Url where the "top" url is String portalTopUrl = Web.serverUrl(req) + ServerConfigurationService.getString("portalPath") + "/"; if (prefix != null) portalTopUrl = portalTopUrl + prefix + "/"; rcontext.put("portalTopUrl", portalTopUrl); rcontext.put("loggedIn", Boolean.valueOf(session.getUserId() != null)); if (placement != null) { Map m = includeTool(res, req, placement); if (m != null) rcontext.put("currentPlacement", m); } boolean loggedIn = session.getUserId() != null; if (site != null) { SiteView siteView = siteHelper.getSitesView(SiteView.View.CURRENT_SITE_VIEW, req, session, siteId ); siteView.setPrefix(prefix); siteView.setResetTools(resetTools); siteView.setToolContextPath(toolContextPath); siteView.setIncludeSummary(includeSummary); siteView.setDoPages(doPages); if ( !siteView.isEmpty() ) { rcontext.put("currentSite", siteView.getRenderContextObject()); } } //List l = siteHelper.convertSitesToMaps(req, mySites, prefix, siteId, myWorkspaceSiteId, // includeSummary, expandSite, resetTools, doPages, toolContextPath, // loggedIn); SiteView siteView = siteHelper.getSitesView(SiteView.View.ALL_SITES_VIEW, req, session, siteId ); siteView.setPrefix(prefix); siteView.setResetTools(resetTools); siteView.setToolContextPath(toolContextPath); siteView.setIncludeSummary(includeSummary); siteView.setDoPages(doPages); siteView.setExpandSite(expandSite); rcontext.put("allSites", siteView.getRenderContextObject()); includeLogin(rcontext, req, session); includeBottom(rcontext); return rcontext; } public boolean isPortletPlacement(Placement placement) { if (placement == null) return false; Tool t = placement.getTool(); if (t == null) return false; Properties toolProps = t.getFinalConfig(); if (toolProps == null) return false; String portletContext = toolProps .getProperty(PortalService.TOOL_PORTLET_CONTEXT_PATH); return (portletContext != null); } public Map includeTool(HttpServletResponse res, HttpServletRequest req, ToolConfiguration placement) throws IOException { // find the tool registered for this ActiveTool tool = ActiveToolManager.getActiveTool(placement.getToolId()); if (tool == null) { // doError(req, res, session); return null; } // Get the Site - we could change the API call in the future to // pass site in, but that would break portals that extend Charon // so for now we simply look this up here. String siteId = placement.getSiteId(); Site site = null; try { site = SiteService.getSiteVisit(siteId); } catch (IdUnusedException e) { site = null; } catch (PermissionException e) { site = null; } // FIXME: This does not look absolutely right, // this appears to say, reset all tools on the page since there // is no filtering of the tool that is bing reset, surely there // should be a check which tool is being reset, rather than all // tools on the page. // let the tool do some the work (include) (see note above) String toolUrl = ServerConfigurationService.getToolUrl() + "/" + Web.escapeUrl(placement.getId()) + "/"; String titleString = Web.escapeHtml(placement.getTitle()); String toolId = Web.escapeHtml(placement.getToolId()); // Reset the tool state if requested if ("true".equals(req.getParameter(portalService.getResetStateParam())) || "true".equals(portalService.getResetState())) { Session s = SessionManager.getCurrentSession(); ToolSession ts = s.getToolSession(placement.getId()); ts.clearAttributes(); } // emit title information // for the reset button boolean showResetButton = !"false".equals(placement.getConfig().getProperty( Portal.TOOLCONFIG_SHOW_RESET_BUTTON)); String resetActionUrl = PortalStringUtil.replaceFirst(toolUrl, "/tool/", "/tool-reset/") + "?panel=Main"; // Reset is different for Portlets if (isPortletPlacement(placement)) { resetActionUrl = Web.serverUrl(req) + ServerConfigurationService.getString("portalPath") + req.getPathInfo() + "?sakai.state.reset=true"; } // for the help button // get the help document ID from the tool config (tool registration // usually). // The help document ID defaults to the tool ID boolean helpEnabledGlobally = ServerConfigurationService.getBoolean( "display.help.icon", true); boolean helpEnabledInTool = !"false".equals(placement.getConfig().getProperty( Portal.TOOLCONFIG_SHOW_HELP_BUTTON)); boolean showHelpButton = helpEnabledGlobally && helpEnabledInTool; String helpActionUrl = ""; if (showHelpButton) { String helpDocUrl = placement.getConfig().getProperty( Portal.TOOLCONFIG_HELP_DOCUMENT_URL); String helpDocId = placement.getConfig().getProperty( Portal.TOOLCONFIG_HELP_DOCUMENT_ID); if (helpDocUrl != null && helpDocUrl.length() > 0) { helpActionUrl = helpDocUrl; } else { if (helpDocId == null || helpDocId.length() == 0) { helpDocId = tool.getId(); } helpActionUrl = ServerConfigurationService.getHelpUrl(helpDocId); } } Map<String, Object> toolMap = new HashMap<String, Object>(); RenderResult result = ToolRenderService.render(this,placement, req, res, getServletContext()); if (result.getJSR168HelpUrl() != null) { toolMap.put("toolJSR168Help", Web.serverUrl(req) + result.getJSR168HelpUrl()); } // Must have site.upd to see the Edit button if (result.getJSR168EditUrl() != null && site != null) { if (SecurityService.unlock(SiteService.SECURE_UPDATE_SITE, site .getReference())) { String editUrl = Web.serverUrl(req) + result.getJSR168EditUrl(); toolMap.put("toolJSR168Edit", editUrl); toolMap.put("toolJSR168EditEncode", URLUtils.encodeUrl(editUrl)); } } toolMap.put("toolRenderResult", result); toolMap.put("hasRenderResult", Boolean.valueOf(true)); toolMap.put("toolUrl", toolUrl); if (isPortletPlacement(placement)) { // If the tool has requested it, pre-fetch render output. String doPreFetch = placement.getConfig().getProperty(Portal.JSR_168_PRE_RENDER); if ( "true".equals(doPreFetch) ) { try { result.getContent(); } catch (Throwable t) { ErrorReporter err = new ErrorReporter(); String str = err.reportFragment(req, res, t); result.setContent(str); } } toolMap.put("toolPlacementIDJS", "_self"); toolMap.put("isPortletPlacement", Boolean.TRUE); } else { toolMap.put("toolPlacementIDJS", Web.escapeJavascript("Main" + placement.getId())); } toolMap.put("toolResetActionUrl", resetActionUrl); toolMap.put("toolResetActionUrlEncode", URLUtils.encodeUrl(resetActionUrl)); toolMap.put("toolTitle", titleString); toolMap.put("toolTitleEncode", URLUtils.encodeUrl(titleString)); toolMap.put("toolShowResetButton", Boolean.valueOf(showResetButton)); toolMap.put("toolShowHelpButton", Boolean.valueOf(showHelpButton)); toolMap.put("toolHelpActionUrl", helpActionUrl); toolMap.put("toolId", toolId); return toolMap; } private String getRequestHandler(HttpServletRequest req) { setupWURFL(); if ( req == null || wurflHolder == null || wurfl == null ) return null; //check sakai.properties to see if auto redirect is enabled //defaults to true - if set to false, skip the PDA check if(!ServerConfigurationService.getBoolean("portal.pda.autoredirect", true)){ return null; } //check if we have a cookie to force classic view, skip the PDA check Cookie c = findCookie(req, Portal.PORTAL_MODE_COOKIE_NAME); if ((c != null) && (c.getValue().equals(Portal.FORCE_CLASSIC_COOKIE_VALUE))) { return null; } Device device = null; try { device = wurfl.getDeviceForRequest(req); } catch (DeviceNotDefinedException e) { //this will be hit a lot, so its at debug level to reduce log traffic if (M_log.isDebugEnabled()) { M_log.debug("Device '" + e.getDeviceId() + "' is not in WURFL"); } return null; } String deviceName = device.getId(); // Not a device recognized by WURFL if (StringUtils.isBlank(deviceName) || deviceName.startsWith("generic") ) { return null; } else { //if this is a mobile device String isMobile = device.getCapability("is_wireless_device"); Boolean isMobileBool = Boolean.valueOf(isMobile); if (isMobileBool.booleanValue()) { Session session = SessionManager.getCurrentSession(); session.setAttribute("is_wireless_device", Boolean.TRUE); return deviceName; } return null; } } /** * Respond to navigation / access requests. * * @param req * The servlet request. * @param res * The servlet response. * @throws javax.servlet.ServletException. * @throws java.io.IOException. */ protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { int stat = PortalHandler.NEXT; try { basicAuth.doLogin(req); if (!ToolRenderService.preprocess(this,req, res, getServletContext())) { return; } // Check to see if the pre-process step has redirected us - if so, // our work is done here - we will likely come back again to finish // our // work. if (res.isCommitted()) { return; } // get the Sakai session Session session = SessionManager.getCurrentSession(); // recognize what to do from the path String option = req.getPathInfo(); //FindBugs thinks this is not used but is passed to the portal handler String[] parts = {}; if (option == null || "/".equals(option)) { // Use the default handler prefix parts = new String[]{"", handlerPrefix}; } else { //get the parts (the first will be "") parts = option.split("/"); } Map<String, PortalHandler> handlerMap = portalService.getHandlerMap(this); PortalHandler ph; String requestHandler = getRequestHandler(req); // begin SAK-19089 // if not logged in and accessing "/" and not from PDA, redirect to gatewaySiteUrl if ((gatewaySiteUrl != null) && (option == null || "/".equals(option)) && (requestHandler == null) && (session.getUserId() == null)) { // redirect to gatewaySiteURL res.sendRedirect(gatewaySiteUrl); return; } // end SAK-19089 if (requestHandler != null){ //Mobile access ph = handlerMap.get("pda"); parts[1] = "pda"; } else{ ph = handlerMap.get(parts[1]); } if (ph != null) { stat = ph.doGet(parts, req, res, session); if (res.isCommitted()) { if (stat != PortalHandler.RESET_DONE) { portalService.setResetState(null); } return; } } if (stat == PortalHandler.NEXT) { List<PortalHandler> urlHandlers; for (Iterator<PortalHandler> i = handlerMap.values().iterator(); i.hasNext();) { ph = i.next(); stat = ph.doGet(parts, req, res, session); if (res.isCommitted()) { if (stat != PortalHandler.RESET_DONE) { portalService.setResetState(null); } return; } // this should be if (stat != PortalHandler.NEXT) { break; } } } if (stat == PortalHandler.NEXT) { doError(req, res, session, Portal.ERROR_SITE); } } catch (Throwable t) { doThrowableError(req, res, t); } // Make sure to clear any reset State at the end of the request unless // we *just* set it if (stat != PortalHandler.RESET_DONE) { portalService.setResetState(null); } } public void doLogin(HttpServletRequest req, HttpServletResponse res, Session session, String returnPath, boolean skipContainer) throws ToolException { try { if (basicAuth.doAuth(req, res)) { // System.err.println("BASIC Auth Request Sent to the Browser // "); return; } } catch (IOException ioex) { throw new ToolException(ioex); } // setup for the helper if needed (Note: in session, not tool session, // special for Login helper) // Note: always set this if we are passed in a return path... a blank // return path is valid... to clean up from // possible abandened previous login attempt -ggolden if (returnPath != null) { // where to go after String returnUrl = Web.returnUrl(req, returnPath); if (req.getQueryString() != null ) returnUrl += "?"+req.getQueryString(); session.setAttribute(Tool.HELPER_DONE_URL, returnUrl); } ActiveTool tool = ActiveToolManager.getActiveTool("sakai.login"); // to skip container auth for this one, forcing things to be handled // internaly, set the "extreme" login path String loginPath = (!forceContainer && skipContainer ? "/xlogin" : "/relogin"); String context = req.getContextPath() + req.getServletPath() + loginPath; tool.help(req, res, context, loginPath); } /** * Process a logout * * @param req * Request object * @param res * Response object * @param session * Current session * @param returnPath * if not null, the path to use for the end-user browser redirect * after the logout is complete. Leave null to use the configured * logged out URL. * @throws IOException */ public void doLogout(HttpServletRequest req, HttpServletResponse res, Session session, String returnPath) throws ToolException { String loggedOutUrl = ServerConfigurationService.getLoggedOutUrl(); if ( returnPath != null ) { loggedOutUrl = loggedOutUrl + returnPath; } session.setAttribute(Tool.HELPER_DONE_URL, loggedOutUrl); ActiveTool tool = ActiveToolManager.getActiveTool("sakai.login"); String context = req.getContextPath() + req.getServletPath() + "/logout"; tool.help(req, res, context, "/logout"); } /** Set up the WURFL objects - to use most classes will * extend the register method and call this setup. */ public void setupWURFL() { // Only do this once if ( wurflLoaded ) return; wurflLoaded = true; try { wurflHolder = (WURFLHolder) getServletContext().getAttribute("net.sourceforge.wurfl.core.WURFLHolder"); if ( wurflHolder == null ) { M_log.warn("WURFL Initialization failed - PDA support may be limited"); } else { wurfl = wurflHolder.getWURFLManager(); M_log.info("WURFL Initialization holder=" + wurflHolder + " manager=" + wurfl); } } catch (Exception e) { M_log.info("WURFL Initialization failed - PDA support may be limited "+e); } } // Read the Wireless Universal Resource File and determine the display size // http://wurfl.sourceforge.net/ public void setupMobileDevice(HttpServletRequest req, PortalRenderContext rcontext) { setupWURFL(); if ( req == null || wurflHolder == null || wurfl == null ) return; Device device = null; try { device = wurfl.getDeviceForRequest(req); } catch (DeviceNotDefinedException e) { //this will be hit a lot, so its at debug level to reduce log traffic M_log.debug("Device '" + e.getDeviceId() + "' is not in WURFL"); return; } // Not a mobile device if ( device == null || device.getId().length() < 1 || device.getId().startsWith("generic") ) return; M_log.debug("device=" + device.getId() + " agent=" + req.getHeader("user-agent")); rcontext.put("wurflDevice",device.getId()); // Check to see if we have too few columns of text String columns = device.getCapability("columns"); { int icol = -1; try { icol = Integer.parseInt(columns); } catch (Exception t) { icol = -1; } if ( icol > 1 && icol < 50 ) { rcontext.put("wurflSmallDisplay",Boolean.TRUE); return; } } // Check if we have too few pixels String width = device.getCapability("resolution_width"); if ( width != null && width.length() > 1 ) { int iwidth = -1; try { iwidth = Integer.parseInt(width); } catch (Throwable t) { iwidth = -1; } if ( iwidth > 1 && iwidth < 400 ) { rcontext.put("wurflSmallDisplay",Boolean.TRUE); return; } } } public PortalRenderContext startPageContext(String siteType, String title, String skin, HttpServletRequest request) { PortalRenderEngine rengine = portalService .getRenderEngine(portalContext, request); PortalRenderContext rcontext = rengine.newRenderContext(request); if (skin == null) { skin = ServerConfigurationService.getString("skin.default"); } String skinRepo = ServerConfigurationService.getString("skin.repo"); rcontext.put("pageSkinRepo", skinRepo); rcontext.put("pageSkin", skin); rcontext.put("pageTitle", Web.escapeHtml(title)); rcontext.put("pageScriptPath", getScriptPath()); rcontext.put("pageTop", Boolean.valueOf(true)); rcontext.put("rloader", rloader); rcontext.put("browser", new BrowserDetector(request)); Session s = SessionManager.getCurrentSession(); rcontext.put("loggedIn", Boolean.valueOf(s.getUserId() != null)); rcontext.put("userId", s.getUserId()); rcontext.put("userEid", s.getUserEid()); rcontext.put("loggedOutUrl",ServerConfigurationService.getLoggedOutUrl()); rcontext.put("portalPath",ServerConfigurationService.getPortalUrl()); rcontext.put("timeoutDialogEnabled",Boolean.valueOf(ServerConfigurationService.getBoolean("timeoutDialogEnabled", true))); rcontext.put("timeoutDialogWarningSeconds", Integer.valueOf(ServerConfigurationService.getInt("timeoutDialogWarningSeconds", 600))); // rcontext.put("sitHelp", Web.escapeHtml(rb.getString("sit_help"))); // rcontext.put("sitReset", Web.escapeHtml(rb.getString("sit_reset"))); if (siteType != null && siteType.length() > 0) { siteType = "class=\"" + siteType + "\""; } else { siteType = ""; } rcontext.put("pageSiteType", siteType); rcontext.put("toolParamResetState", portalService.getResetStateParam()); // Get the tool header properties Properties props = toolHeaderProperties(skin); for(Object okey : props.keySet() ) { String key = (String) okey; String keyund = key.replace('.','_'); rcontext.put(keyund,props.getProperty(key)); } // Copy the minimization preferences to the context String minStr = ServerConfigurationService.getString("portal.allow.minimize.tools","true"); rcontext.put("portal_allow_minimize_tools",Boolean.valueOf( "true".equals(minStr) ) ) ; minStr = ServerConfigurationService.getString("portal.allow.minimize.navigation","false"); rcontext.put("portal_allow_minimize_navigation",Boolean.valueOf( "true".equals(minStr) ) ) ; minStr = ServerConfigurationService.getString("portal.allow.auto.minimize","true"); rcontext.put("portal_allow_auto_minimize",Boolean.valueOf( "true".equals(minStr) ) ) ; // copy the add link to /mobile to the content String addMLnk = ServerConfigurationService.getString("portal.add.mobile.link","false"); // show the mobile link or not Session session = SessionManager.getCurrentSession(); if (session.getAttribute("is_wireless_device") == null && request != null) { // when user logs out, all session variables are cleaned, this is to reset the is_wireless_device attribute in portal Device device = null; try { device = wurfl.getDeviceForRequest(request); String deviceName = device.getId(); // Not a device recognized by WURFL if (StringUtils.isBlank(deviceName) || deviceName.startsWith("generic") ) { } else { //if this is a mobile device String isMobile = device.getCapability("is_wireless_device"); Boolean isMobileBool = Boolean.valueOf(isMobile); if (isMobileBool.booleanValue()) { session.setAttribute("is_wireless_device", Boolean.TRUE); } } } catch (DeviceNotDefinedException e) { //this will be hit a lot, so its at debug level to reduce log traffic if (M_log.isDebugEnabled()) { M_log.debug("Device '" + e.getDeviceId() + "' is not in WURFL"); } } } boolean isWirelessDevice = session.getAttribute("is_wireless_device") != null ? ((Boolean) session.getAttribute("is_wireless_device")).booleanValue():false; rcontext.put("portal_add_mobile_link",Boolean.valueOf( "true".equals(addMLnk) && isWirelessDevice ) ) ; return rcontext; } /** * Respond to data posting requests. * * @param req * The servlet request. * @param res * The servlet response. * @throws ServletException * @throws IOException */ protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { int stat = PortalHandler.NEXT; try { basicAuth.doLogin(req); if (!ToolRenderService.preprocess(this,req, res, getServletContext())) { // System.err.println("POST FAILED, REDIRECT ?"); return; } // Check to see if the pre-process step has redirected us - if so, // our work is done here - we will likely come back again to finish // our // work. T if (res.isCommitted()) { return; } // get the Sakai session Session session = SessionManager.getCurrentSession(); // recognize what to do from the path String option = req.getPathInfo(); // if missing, we have a stray post if ((option == null) || ("/".equals(option))) { doError(req, res, session, ERROR_SITE); return; } // get the parts (the first will be "") String[] parts = option.split("/"); Map<String, PortalHandler> handlerMap = portalService.getHandlerMap(this); PortalHandler ph; String requestHandler = getRequestHandler(req); // SAK-18955: do not use PDAHandler for relogin if ((! parts[1].equals("relogin")) && (requestHandler!=null)){ //Mobile access ph = handlerMap.get("pda"); parts[1] = "pda"; }else{ ph = handlerMap.get(parts[1]); } if (ph != null) { stat = ph.doPost(parts, req, res, session); if (res.isCommitted()) { return; } } if (stat == PortalHandler.NEXT) { List<PortalHandler> urlHandlers; for (Iterator<PortalHandler> i = handlerMap.values().iterator(); i.hasNext();) { ph = i.next(); stat = ph.doPost(parts, req, res, session); if (res.isCommitted()) { return; } // this should be if (stat != PortalHandler.NEXT) { break; } } } if (stat == PortalHandler.NEXT) { doError(req, res, session, Portal.ERROR_SITE); } } catch (Throwable t) { doThrowableError(req, res, t); } } /* * Checks to see which form of tool or page placement we have. The normal * placement is a GUID. However when the parameter sakai.site is added to * the request, the placement can be of the form sakai.resources. This * routine determines which form of the placement id, and if this is the * second type, performs the lookup and returns the GUID of the placement. * If we cannot resolve the placement, we simply return the passed in * placement ID. If we cannot visit the site, we send the user to login * processing and return null to the caller. * * If the reference is to the magical, indexical MyWorkspace site ('~') * then replace ~ by their My Workspace. Give them a chance to login * if necessary. */ public String getPlacement(HttpServletRequest req, HttpServletResponse res, Session session, String placementId, boolean doPage) throws ToolException { String siteId = req.getParameter(PARAM_SAKAI_SITE); if (siteId == null) return placementId; // Standard placement // Try to resolve the indexical MyWorkspace reference if (myWorkspaceSiteId.equals(siteId)) { // If not logged in then allow login. You can't go to your workspace if // you aren't known to the system. if (session.getUserId() == null) { doLogin(req, res, session, req.getPathInfo(), false); } // If the login was successful lookup the myworkworkspace site. if (session.getUserId() != null) { siteId=getUserEidBasedSiteId(session.getUserEid()); } } // find the site, for visiting // Sites like the !gateway site allow visits by anonymous Site site = null; try { site = getSiteHelper().getSiteVisit(siteId); } catch (IdUnusedException e) { return placementId; // cannot resolve placement } catch (PermissionException e) { // If we are not logged in, try again after we log in, otherwise // punt if (session.getUserId() == null) { doLogin(req, res, session, req.getPathInfo(), false); return null; } return placementId; // cannot resolve placement } if (site == null) return placementId; ToolConfiguration toolConfig = site.getToolForCommonId(placementId); if (toolConfig == null) return placementId; if (doPage) { return toolConfig.getPageId(); } else { return toolConfig.getId(); } } // NOTE: This code is duplicated in ToolPortal.java - make sure to change // both places public Properties toolHeaderProperties(String skin) { return toolHeaderProperties(skin, null); } public Properties toolHeaderProperties(String skin, Placement placement) { Properties retval = new Properties(); // setup html information that the tool might need (skin, body on load, // js includes, etc). if (skin == null || skin.length() == 0) skin = ServerConfigurationService.getString("skin.default"); String skinRepo = ServerConfigurationService.getString("skin.repo"); String headCssToolBase = "<link href=\"" + skinRepo + "/tool_base.css\" type=\"text/css\" rel=\"stylesheet\" media=\"all\" />\n"; String headCssToolSkin = "<link href=\"" + skinRepo + "/" + skin + "/tool.css\" type=\"text/css\" rel=\"stylesheet\" media=\"all\" />\n"; String headCss = headCssToolBase + headCssToolSkin; Editor editor = portalService.getActiveEditor(placement); String preloadScript = editor.getPreloadScript() == null ? "" : "<script type=\"text/javascript\" language=\"JavaScript\">" + editor.getPreloadScript() + "</script>\n"; String editorScript = editor.getEditorUrl() == null ? "" : "<script type=\"text/javascript\" language=\"JavaScript\" src=\"" + editor.getEditorUrl() + "\"></script>\n"; String launchScript = editor.getLaunchUrl() == null ? "" : "<script type=\"text/javascript\" language=\"JavaScript\" src=\"" + editor.getLaunchUrl() + "\"></script>\n"; StringBuilder headJs = new StringBuilder(); headJs.append("<script type=\"text/javascript\" language=\"JavaScript\" src=\"/library/js/headscripts.js\"></script>\n"); headJs.append("<script type=\"text/javascript\" language=\"JavaScript\">var sakai = sakai || {}; sakai.editor = sakai.editor || {}; \n"); headJs.append("sakai.editor.collectionId = '" + portalService.getBrowserCollectionId(placement) + "';\n"); headJs.append("sakai.editor.enableResourceSearch = " + EditorConfiguration.enableResourceSearch() + ";</script>\n"); headJs.append(preloadScript); headJs.append(editorScript); headJs.append(launchScript); // TODO: Should we include jquery here? See includeStandardHead.vm String head = headCss + headJs.toString(); retval.setProperty("sakai.html.head", head); retval.setProperty("sakai.html.head.css", headCss); retval.setProperty("sakai.html.head.css.base", headCssToolBase); retval.setProperty("sakai.html.head.css.skin", headCssToolSkin); retval.setProperty("sakai.html.head.js", headJs.toString()); return retval; } public void setupForward(HttpServletRequest req, HttpServletResponse res, Placement p, String skin) throws ToolException { // Get the tool header properties Properties props = toolHeaderProperties(skin, p); for(Object okey : props.keySet() ) { String key = (String) okey; req.setAttribute(key,props.getProperty(key)); } StringBuilder bodyonload = new StringBuilder(); if (p != null) { String element = Web.escapeJavascript("Main" + p.getId()); bodyonload.append("setMainFrameHeight('" + element + "');"); } bodyonload.append("setFocus(focus_path);"); req.setAttribute("sakai.html.body.onload", bodyonload.toString()); portalService.getRenderEngine(portalContext, req).setupForward(req, res, p, skin); } /** * Forward to the tool - but first setup JavaScript/CSS etc that the tool * will render */ public void forwardTool(ActiveTool tool, HttpServletRequest req, HttpServletResponse res, Placement p, String skin, String toolContextPath, String toolPathInfo) throws ToolException { // if there is a stored request state, and path, extract that from the // session and reinstance it // let the tool do the the work (forward) if (enableDirect) { StoredState ss = portalService.getStoredState(); if (ss == null || !toolContextPath.equals(ss.getToolContextPath())) { setupForward(req, res, p, skin); req.setAttribute(ToolURL.MANAGER, new ToolURLManagerImpl(res)); tool.forward(req, res, p, toolContextPath, toolPathInfo); } else { M_log.debug("Restoring StoredState [" + ss + "]"); HttpServletRequest sreq = ss.getRequest(req); Placement splacement = ss.getPlacement(); String stoolContext = ss.getToolContextPath(); String stoolPathInfo = ss.getToolPathInfo(); ActiveTool stool = ActiveToolManager.getActiveTool(p.getToolId()); String sskin = ss.getSkin(); setupForward(sreq, res, splacement, sskin); req.setAttribute(ToolURL.MANAGER, new ToolURLManagerImpl(res)); stool.forward(sreq, res, splacement, stoolContext, stoolPathInfo); // this is correct as we have checked the context path of the // tool portalService.setStoredState(null); } } else { setupForward(req, res, p, skin); req.setAttribute(ToolURL.MANAGER, new ToolURLManagerImpl(res)); tool.forward(req, res, p, toolContextPath, toolPathInfo); } } public void forwardPortal(ActiveTool tool, HttpServletRequest req, HttpServletResponse res, ToolConfiguration p, String skin, String toolContextPath, String toolPathInfo) throws ToolException, IOException { String portalPath = ServerConfigurationService.getString("portalPath", "/portal"); // if there is a stored request state, and path, extract that from the // session and reinstance it // generate the forward to the tool page placement String portalPlacementUrl = portalPath + getPortalPageUrl(p); res.sendRedirect(portalPlacementUrl); return; } public String getPortalPageUrl(ToolConfiguration p) { SitePage sitePage = p.getContainingPage(); String page = getSiteHelper().lookupPageToAlias(p.getSiteId(), sitePage); if (page == null) { // Fall back to default of using the page Id. page = p.getPageId(); } return "/site/" + p.getSiteId() + "/page/" + page; } protected String getScriptPath() { return "/library/js/"; } /** * Access the Servlet's information display. * * @return servlet information. */ public String getServletInfo() { return "Sakai Charon Portal"; } public void includeBottom(PortalRenderContext rcontext) { if (rcontext.uses(INCLUDE_BOTTOM)) { rcontext.put("pagepopup", false); String copyright = ServerConfigurationService .getString("bottom.copyrighttext"); String service = ServerConfigurationService.getString("ui.service", "Sakai"); String serviceVersion = ServerConfigurationService.getString( "version.service", "?"); String sakaiVersion = ServerConfigurationService.getString("version.sakai", "?"); String kernelVersion = ServerConfigurationService.getString("version.kernel", "?"); String server = ServerConfigurationService.getServerId(); String[] bottomNav = ServerConfigurationService.getStrings("bottomnav"); String[] poweredByUrl = ServerConfigurationService.getStrings("powered.url"); String[] poweredByImage = ServerConfigurationService .getStrings("powered.img"); String[] poweredByAltText = ServerConfigurationService .getStrings("powered.alt"); { List<Object> l = new ArrayList<Object>(); if ((bottomNav != null) && (bottomNav.length > 0)) { for (int i = 0; i < bottomNav.length; i++) { l.add(bottomNav[i]); } } rcontext.put("bottomNav", l); } // rcontext.put("bottomNavSitNewWindow", // Web.escapeHtml(rb.getString("site_newwindow"))); if ((poweredByUrl != null) && (poweredByImage != null) && (poweredByAltText != null) && (poweredByUrl.length == poweredByImage.length) && (poweredByUrl.length == poweredByAltText.length)) { { List<Object> l = new ArrayList<Object>(); for (int i = 0; i < poweredByUrl.length; i++) { Map<String, Object> m = new HashMap<String, Object>(); m.put("poweredByUrl", poweredByUrl[i]); m.put("poweredByImage", poweredByImage[i]); m.put("poweredByAltText", poweredByAltText[i]); l.add(m); } rcontext.put("bottomNavPoweredBy", l); } } else { List<Object> l = new ArrayList<Object>(); Map<String, Object> m = new HashMap<String, Object>(); m.put("poweredByUrl", "http://sakaiproject.org"); m.put("poweredByImage", "/library/image/sakai_powered.gif"); m.put("poweredByAltText", "Powered by Sakai"); l.add(m); rcontext.put("bottomNavPoweredBy", l); } rcontext.put("bottomNavService", service); rcontext.put("bottomNavCopyright", copyright); rcontext.put("bottomNavServiceVersion", serviceVersion); rcontext.put("bottomNavSakaiVersion", sakaiVersion); rcontext.put("bottomNavKernelVersion", kernelVersion); rcontext.put("bottomNavServer", server); } } public void includeLogin(PortalRenderContext rcontext, HttpServletRequest req, Session session) { if (rcontext.uses(INCLUDE_LOGIN)) { // for the main login/out link String logInOutUrl = Web.serverUrl(req); String message = null; String image1 = null; // for a possible second link String logInOutUrl2 = null; String message2 = null; String image2 = null; // for showing user display name and id next to logout (SAK-10492) String loginUserDispName = null; String loginUserDispId = null; boolean displayUserloginInfo = ServerConfigurationService. getBoolean("display.userlogin.info", false); // check for the top.login (where the login fields are present // instead // of a login link, but ignore it if container.login is set boolean topLogin = Boolean.TRUE.toString().equalsIgnoreCase( ServerConfigurationService.getString("top.login")); boolean containerLogin = Boolean.TRUE.toString().equalsIgnoreCase( ServerConfigurationService.getString("container.login")); if (containerLogin) topLogin = false; // if not logged in they get login if (session.getUserId() == null) { // we don't need any of this if we are doing top login if (!topLogin) { logInOutUrl += ServerConfigurationService.getString("portalPath") + "/login"; // let the login url be overridden by configuration String overrideLoginUrl = StringUtils .trimToNull(ServerConfigurationService.getString("login.url")); if (overrideLoginUrl != null) logInOutUrl = overrideLoginUrl; // check for a login text override message = StringUtils.trimToNull(ServerConfigurationService .getString("login.text")); if (message == null) message = rloader.getString("log.login"); // check for an image for the login image1 = StringUtils.trimToNull(ServerConfigurationService .getString("login.icon")); // check for a possible second, xlogin link if (Boolean.TRUE.toString().equalsIgnoreCase( ServerConfigurationService.getString("xlogin.enabled"))) { // get the text and image as configured message2 = StringUtils.trimToNull(ServerConfigurationService .getString("xlogin.text")); image2 = StringUtils.trimToNull(ServerConfigurationService .getString("xlogin.icon")); logInOutUrl2 = ServerConfigurationService.getString("portalPath") + "/xlogin"; } } } // if logged in they get logout else { logInOutUrl += ServerConfigurationService.getString("portalPath") + "/logout"; // get current user display id and name if (displayUserloginInfo) { User thisUser = UserDirectoryService.getCurrentUser(); loginUserDispId = Validator.escapeHtml(thisUser.getDisplayId()); loginUserDispName = Validator.escapeHtml(thisUser.getDisplayName()); } // check for a logout text override message = StringUtils.trimToNull(ServerConfigurationService .getString("logout.text")); if (message == null) message = rloader.getString("sit_log"); // check for an image for the logout image1 = StringUtils.trimToNull(ServerConfigurationService .getString("logout.icon")); // since we are doing logout, cancel top.login topLogin = false; } rcontext.put("loginTopLogin", Boolean.valueOf(topLogin)); if (!topLogin) { rcontext.put("loginLogInOutUrl", logInOutUrl); rcontext.put("loginMessage", message); rcontext.put("loginImage1", image1); rcontext.put("loginHasImage1", Boolean.valueOf(image1 != null)); rcontext.put("loginLogInOutUrl2", logInOutUrl2); rcontext.put("loginHasLogInOutUrl2", Boolean .valueOf(logInOutUrl2 != null)); rcontext.put("loginMessage2", message2); rcontext.put("loginImage2", image2); rcontext.put("loginHasImage2", Boolean.valueOf(image2 != null)); // put out the links version // else put out the fields that will send to the login interface } else { String eidWording = null; String pwWording = null; eidWording = StringUtils.trimToNull(rloader.getString("log.userid")); pwWording = StringUtils.trimToNull(rloader.getString("log.pass")); if (eidWording == null) eidWording = "eid"; if (pwWording == null) pwWording = "pw"; String loginWording = rloader.getString("log.login"); rcontext.put("loginPortalPath", ServerConfigurationService .getString("portalPath")); rcontext.put("loginEidWording", eidWording); rcontext.put("loginPwWording", pwWording); rcontext.put("loginWording", loginWording); // setup for the redirect after login session.setAttribute(Tool.HELPER_DONE_URL, ServerConfigurationService .getPortalUrl()); } if (displayUserloginInfo) { rcontext.put("loginUserDispName", loginUserDispName); rcontext.put("loginUserDispId", loginUserDispId); } rcontext.put("displayUserloginInfo", displayUserloginInfo && loginUserDispId != null); } } /** * @param rcontext * @param res * @param req * @param session * @param site * @param page * @param toolContextPath * @param portalPrefix * @return * @throws IOException */ public void includeWorksite(PortalRenderContext rcontext, HttpServletResponse res, HttpServletRequest req, Session session, Site site, SitePage page, String toolContextPath, String portalPrefix) throws IOException { worksiteHandler.includeWorksite(rcontext, res, req, session, site, page, toolContextPath, portalPrefix); } /** * Initialize the servlet. * * @param config * The servlet config. * @throws ServletException */ public void init(ServletConfig config) throws ServletException { super.init(config); portalContext = config.getInitParameter("portal.context"); if (portalContext == null || portalContext.length() == 0) { portalContext = DEFAULT_PORTAL_CONTEXT; } boolean findPageAliases = ServerConfigurationService.getBoolean("portal.use.page.aliases", false); siteHelper = new PortalSiteHelperImpl(this, findPageAliases); portalService = org.sakaiproject.portal.api.cover.PortalService.getInstance(); M_log.info("init()"); forceContainer = ServerConfigurationService.getBoolean("login.use.xlogin.to.relogin", true); handlerPrefix = ServerConfigurationService.getString("portal.handler.default", "site"); gatewaySiteUrl = ServerConfigurationService.getString("gatewaySiteUrl", null); basicAuth = new BasicAuth(); basicAuth.init(); enableDirect = portalService.isEnableDirect(); // do this before adding handlers to prevent handlers registering 2 // times. // if the handlers were already there they will be re-registered, // but when they are added again, they will be replaced. // warning messages will appear, but the end state will be the same. portalService.addPortal(this); galleryHandler = new GalleryHandler(); worksiteHandler = new WorksiteHandler(); siteHandler = new SiteHandler(); addHandler(siteHandler); addHandler(new SiteResetHandler()); addHandler(new ToolHandler()); addHandler(new ToolResetHandler()); addHandler(new PageHandler()); addHandler(worksiteHandler); addHandler(new WorksiteResetHandler()); addHandler(new RssHandler()); addHandler(new PDAHandler()); addHandler(new AtomHandler()); addHandler(new OpmlHandler()); addHandler(galleryHandler); addHandler(new GalleryResetHandler()); addHandler(new NavLoginHandler()); addHandler(new PresenceHandler()); addHandler(new HelpHandler()); addHandler(new ReLoginHandler()); addHandler(new LoginHandler()); addHandler(new XLoginHandler()); addHandler(new LogoutHandler()); addHandler(new ErrorDoneHandler()); addHandler(new ErrorReportHandler()); addHandler(new StaticStylesHandler()); addHandler(new StaticScriptsHandler()); addHandler(new DirectToolHandler()); addHandler(new RoleSwitchHandler()); addHandler(new RoleSwitchOutHandler()); addHandler(new TimeoutDialogHandler()); } /** * Register a handler for a URL stub * * @param handler */ private void addHandler(PortalHandler handler) { portalService.addHandler(this, handler); } private void removeHandler(String urlFragment) { portalService.removeHandler(this, urlFragment); } /** * Send the POST request to login * * @param req * @param res * @param session * @throws IOException */ protected void postLogin(HttpServletRequest req, HttpServletResponse res, Session session, String loginPath) throws ToolException { ActiveTool tool = ActiveToolManager.getActiveTool("sakai.login"); String context = req.getContextPath() + req.getServletPath() + "/" + loginPath; tool.help(req, res, context, "/" + loginPath); } /** * Output some session information * * @param rcontext * The print writer * @param html * If true, output in HTML, else in text. */ protected void showSession(PortalRenderContext rcontext, boolean html) { // get the current user session information Session s = SessionManager.getCurrentSession(); rcontext.put("sessionSession", s); ToolSession ts = SessionManager.getCurrentToolSession(); rcontext.put("sessionToolSession", ts); } public void sendResponse(PortalRenderContext rcontext, HttpServletResponse res, String template, String contentType) throws IOException { // headers if (contentType == null) { res.setContentType("text/html; charset=UTF-8"); } else { res.setContentType(contentType); } res.addDateHeader("Expires", System.currentTimeMillis() - (1000L * 60L * 60L * 24L * 365L)); res.addDateHeader("Last-Modified", System.currentTimeMillis()); res .addHeader("Cache-Control", "no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0"); res.addHeader("Pragma", "no-cache"); // get the writer PrintWriter out = res.getWriter(); try { PortalRenderEngine rengine = rcontext.getRenderEngine(); rengine.render(template, rcontext, out); } catch (Exception e) { throw new RuntimeException("Failed to render template ", e); } } /** * Returns the type ("course", "project", "workspace", "mySpecialSiteType", * etc) of the given site; special handling of returning "workspace" for * user workspace sites. This method is tightly coupled to site skinning. */ public String calcSiteType(String siteId) { String siteType = null; if (siteId != null && siteId.length() != 0) { if (SiteService.isUserSite(siteId)) { siteType = "workspace"; } else { try { siteType = SiteService.getSite(siteId).getType(); } catch (IdUnusedException ex) { // ignore, the site wasn't found } } } if (siteType != null && siteType.trim().length() == 0) siteType = null; return siteType; } private void logXEntry() { Exception e = new Exception(); StackTraceElement se = e.getStackTrace()[1]; M_log.info("Log marker " + se.getMethodName() + ":" + se.getFileName() + ":" + se.getLineNumber()); } /** * Check for any just expired sessions and redirect * * @return true if we redirected, false if not */ public boolean redirectIfLoggedOut(HttpServletResponse res) throws IOException { // if we are in a newly created session where we had an invalid // (presumed timed out) session in the request, // send script to cause a sakai top level redirect if (ThreadLocalManager.get(SessionManager.CURRENT_INVALID_SESSION) != null) { String loggedOutUrl = ServerConfigurationService.getLoggedOutUrl(); sendPortalRedirect(res, loggedOutUrl); return true; } return false; } /** * Send a redirect so our Portal window ends up at the url, via javascript. * * @param url * The redirect url */ protected void sendPortalRedirect(HttpServletResponse res, String url) throws IOException { PortalRenderContext rcontext = startPageContext("", null, null, null); rcontext.put("redirectUrl", url); sendResponse(rcontext, res, "portal-redirect", null); } /** * Compute the string that will identify the user site for this user - use * the EID if possible * * @param userId * The user id * @return The site "ID" but based on the user EID */ public String getUserEidBasedSiteId(String userId) { try { // use the user EID String eid = UserDirectoryService.getUserEid(userId); return SiteService.getUserSiteId(eid); } catch (UserNotDefinedException e) { M_log.warn("getUserEidBasedSiteId: user id not found for eid: " + userId); return SiteService.getUserSiteId(userId); } } /* (non-Javadoc) * @see org.sakaiproject.portal.api.Portal#getPageFilter() */ public PageFilter getPageFilter() { return pageFilter; } /* (non-Javadoc) * @see org.sakaiproject.portal.api.Portal#setPageFilter(org.sakaiproject.portal.api.PageFilter) */ public void setPageFilter(PageFilter pageFilter) { this.pageFilter = pageFilter; } /* (non-Javadoc) * @see org.sakaiproject.portal.api.Portal#getSiteHelper() */ public PortalSiteHelper getSiteHelper() { return this.siteHelper; } /* (non-Javadoc) * @see org.sakaiproject.portal.api.Portal#getSiteNeighbourhoodService() */ public SiteNeighbourhoodService getSiteNeighbourhoodService() { return portalService.getSiteNeighbourhoodService(); } /** * Find a cookie by this name from the request * * @param req * The servlet request. * @param name * The cookie name * @return The cookie of this name in the request, or null if not found. */ public Cookie findCookie(HttpServletRequest req, String name) { Cookie[] cookies = req.getCookies(); if (cookies != null) { for (int i = 0; i < cookies.length; i++) { if (cookies[i].getName().equals(name)) { return cookies[i]; } } } return null; } }