/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/portal/trunk/portal-impl/impl/src/java/org/sakaiproject/portal/charon/CharonPortal.java $ * $Id: CharonPortal.java 132744 2013-12-18 15:34:44Z 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.opensource.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.text.DateFormat; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Vector; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; 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.PortalService; import org.sakaiproject.portal.api.StoredState; import org.sakaiproject.portal.render.api.RenderResult; import org.sakaiproject.portal.render.cover.ToolRenderService; import org.sakaiproject.portal.util.ErrorReporter; import org.sakaiproject.portal.util.URLUtils; import org.sakaiproject.portal.util.ToolURLManagerImpl; 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.Preferences; import org.sakaiproject.user.api.UserNotDefinedException; import org.sakaiproject.user.cover.PreferencesService; import org.sakaiproject.user.cover.UserDirectoryService; import org.sakaiproject.util.BasicAuth; 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.0 * @version $Rev: 132744 $ * */ public class CharonPortal extends HttpServlet { /** Our log (commons). */ private static Log M_log = LogFactory.getLog(CharonPortal.class); /** messages. */ private static ResourceLoader rb = new ResourceLoader("sitenav"); /** * Session attribute root for storing a site's last page visited - just * append the site id. */ protected static final String ATTR_SITE_PAGE = "sakai.portal.site."; /** * Parameter value to allow anonymous users of gallery mode to be sent to * the gateway site as anonymous user (like the /portal URL) instead of * making them log in (like worksite, site, and tool URLs). */ protected static final String PARAM_FORCE_LOGIN = "force.login"; /** Configuration option to enable/disable state reset on navigation change */ protected static final String CONFIG_AUTO_RESET = "portal.experimental.auto.reset"; /** Parameter value to indicate to look up a tool ID within a site */ protected static final String PARAM_SAKAI_SITE = "sakai.site"; /** ThreadLocal attribute set while we are processing an error. */ protected static final String ATTR_ERROR = "org.sakaiproject.portal.error"; /** Error response modes. */ protected static final int ERROR_SITE = 0; protected static final int ERROR_GALLERY = 1; protected static final int ERROR_WORKSITE = 2; /** * Names of tool config/registration attributes that control the rendering * of the tool's titlebar */ private static final String TOOLCONFIG_SHOW_RESET_BUTTON = "reset.button"; private static final String TOOLCONFIG_SHOW_HELP_BUTTON = "help.button"; private static final String TOOLCONFIG_HELP_DOCUMENT_ID = "help.id"; private static final String TOOLCONFIG_HELP_DOCUMENT_URL = "help.url"; private BasicAuth basicAuth = null; private boolean enableDirect = false; private PortalService portalService; private ToolHelperImpl toolHelper = new ToolHelperImpl(); /** * Shutdown the servlet. */ public void destroy() { M_log.info("destroy()"); super.destroy(); } protected 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: { doSite(req, res, session, "!error", null, req.getContextPath() + req.getServletPath()); break; } case ERROR_GALLERY: { doGallery(req, res, session, "!error", null, req.getContextPath() + req.getServletPath()); break; } case ERROR_WORKSITE: { 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","Sakai") + " : Portal"; // start the response PrintWriter out = startResponse(res, title, null, false); // Show session information out.println("<h2>Session</h2>"); showSession(out, true); out.println("<h2>Unknown Request</h2>"); Web.snoop(out, true, getServletConfig(), req); // end the response endResponse(out); } protected void doThrowableError(HttpServletRequest req, HttpServletResponse res, Throwable t) { ErrorReporter err = new ErrorReporter(); err.report(req, res, t); } protected void doGallery(HttpServletRequest req, HttpServletResponse res, Session session, String siteId, String pageId, String toolContextPath) throws ToolException, IOException { // check to default site id if (siteId == null) { if (session.getUserId() == null) { String forceLogin = req.getParameter(PARAM_FORCE_LOGIN); if (forceLogin == null || "yes".equalsIgnoreCase(forceLogin) || "true".equalsIgnoreCase(forceLogin)) { doLogin(req, res, session, URLUtils.getSafePathInfo(req), false); return; } siteId = ServerConfigurationService.getGatewaySiteId(); } else { siteId = SiteService.getUserSiteId(session.getUserId()); } } // if no page id, see if there was a last page visited for this site if (pageId == null) { pageId = (String) session.getAttribute(ATTR_SITE_PAGE + siteId); } // find the site, for visiting Site site = null; try { site = getSiteVisit(siteId); } catch (IdUnusedException e) { doError(req, res, session, ERROR_GALLERY); return; } catch (PermissionException e) { // if not logged in, give them a chance if (session.getUserId() == null) { doLogin(req, res, session, URLUtils.getSafePathInfo(req), false); } else { doError(req, res, session, ERROR_GALLERY); } return; } // find the page, or use the first page if pageId not found SitePage page = site.getPage(pageId); if (page == null) { List pages = site.getOrderedPages(); if (!pages.isEmpty()) { page = (SitePage) pages.get(0); } } if (page == null) { doError(req, res, session, ERROR_GALLERY); return; } // store the last page visited session.setAttribute(ATTR_SITE_PAGE + siteId, page.getId()); // form a context sensitive title String title = ServerConfigurationService.getString("ui.service","Sakai") + " : " + site.getTitle() + " : " + page.getTitle(); // start the response PrintWriter out = startResponse(res, title, site.getSkin(), true); // the 'little' top area includeGalleryNav(out, req, session, siteId); String siteType = calcSiteType(siteId); out.println("<div id=\"container\"" + ((siteType != null) ? " class=\"" + siteType + "\"" : "") + ">"); includeWorksite(req, res, session, site, page, toolContextPath, "gallery"); out.println("<div>"); includeBottom(out); // end the response endResponse(out); } protected void doGalleryTabs(HttpServletRequest req, HttpServletResponse res, Session session, String siteId) throws IOException { String skin = getSiteSkin(siteId); // start the response PrintWriter out = startResponse(res, "Site Navigation", skin, false); // Remove the logout button from gallery since it is designed to be // included within // some other application (like a portal) which will want to control // logout. // includeTabs(out, req, session, siteId, "gallery", true); includeTabs(out, req, session, siteId, "gallery", false); // end the response endResponse(out); } /** * Respond to navigation / access requests. * * @param req * The servlet request. * @param res * The servlet response. * @throws ServletException * @throws IOException */ protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { boolean resetDone = false; try { basicAuth.doLogin(req); // get the Sakai session Session session = SessionManager.getCurrentSession(); // recognize what to do from the path String option = URLUtils.getSafePathInfo(req); // if missing, set it to home or gateway if ((option == null) || ("/".equals(option))) { if (session.getUserId() == null) { option = "/site/" + ServerConfigurationService.getGatewaySiteId(); } else { option = "/site/" + SiteService.getUserSiteId(session.getUserId()); } } // get the parts (the first will be "") String[] parts = option.split("/"); // recognize and dispatch the 'tool' option: [1] = "tool", [2] = // placement id (of a site's tool placement), rest for the tool if ((parts.length > 2) && (parts[1].equals("tool"))) { // Resolve the placements of the form // /portal/tool/sakai.resources?sakai.site=~csev String toolPlacement = getPlacement(req, res, session, parts[2], false); if (toolPlacement == null) { return; } parts[2] = toolPlacement; doTool(req, res, session, parts[2], req.getContextPath() + req.getServletPath() + Web.makePath(parts, 1, 3), Web.makePath( parts, 3, parts.length)); } else if (enableDirect && (parts.length > 2) && (parts[1].equals("directtool"))) { // Resolve the placements of the form // /portal/tool/sakai.resources?sakai.site=~csev String toolPlacement = getPlacement(req, res, session, parts[2], false); if (toolPlacement == null) { return; } parts[2] = toolPlacement; doDirectTool(req, res, session, parts[2], req.getContextPath() + req.getServletPath() + Web.makePath(parts, 1, 3), Web.makePath( parts, 3, parts.length)); } // These reet urls simply set a session value to indicate to reset // state and then redirect // This is necessary os that hte URL is clean and we do not see // resets on refresh else if ((parts.length > 2) && (parts[1].equals("tool-reset"))) { String toolUrl = req.getContextPath() + "/tool" + Web.makePath(parts, 2, parts.length); // Make sure to add the parameters such as panel=Main String queryString = Validator.generateQueryString(req); if (queryString != null) { toolUrl = toolUrl + "?" + queryString; } portalService.setResetState("true"); resetDone = true; res.sendRedirect(toolUrl); } /** * Title frames were no longer used in 2.3 and are not supported in * 2.4 so we emit a WARN message here to help people with derived * classes figure out the new way. */ // TODO: Remove after 2.4 else if ((parts.length > 2) && (parts[1].equals("title"))) { // Resolve the placements of the form // /portal/title/sakai.resources?sakai.site=~csev String toolPlacement = getPlacement(req, res, session, parts[2], false); if (toolPlacement == null) { return; } parts[2] = toolPlacement; doTitle(req, res, session, parts[2], req.getContextPath() + req.getServletPath() + Web.makePath(parts, 1, 3), Web.makePath( parts, 3, parts.length)); } // recognize a dispatch the 'page' option (tools on a page) else if ((parts.length == 3) && (parts[1].equals("page"))) { // Resolve the placements of the form // /portal/page/sakai.resources?sakai.site=~csev String pagePlacement = getPlacement(req, res, session, parts[2], true); if (pagePlacement == null) { return; } parts[2] = pagePlacement; doPage(req, res, session, parts[2], req.getContextPath() + req.getServletPath()); } // recognize a dispatch the 'worksite' option (pages navigation + // tools on a page) else if ((parts.length >= 3) && (parts[1].equals("worksite"))) { // recognize an optional page/pageid String pageId = null; if ((parts.length == 5) && (parts[3].equals("page"))) { pageId = parts[4]; } doWorksite(req, res, session, parts[2], pageId, req.getContextPath() + req.getServletPath()); } // recognize a dispatch the 'gallery' option (site tabs + pages // navigation + tools on a page) else if ((parts.length >= 2) && (parts[1].equals("gallery"))) { // recognize an optional page/pageid String pageId = null; if ((parts.length == 5) && (parts[3].equals("page"))) { pageId = parts[4]; } // site might be specified String siteId = null; if (parts.length >= 3) { siteId = parts[2]; } doGallery(req, res, session, siteId, pageId, req.getContextPath() + req.getServletPath()); } // recognize a dispatch the 'site' option (site logo and tabs + // pages navigation + tools on a page) else if ((parts.length >= 2) && (parts[1].equals("site"))) { // recognize an optional page/pageid String pageId = null; if ((parts.length == 5) && (parts[3].equals("page"))) { pageId = parts[4]; } // site might be specified String siteId = null; if (parts.length >= 3) { siteId = parts[2]; } doSite(req, res, session, siteId, pageId, req.getContextPath() + req.getServletPath()); } // recognize site tabs else if ((parts.length == 3) && (parts[1].equals("site_tabs"))) { doSiteTabs(req, res, session, parts[2]); } // recognize gallery tabs else if ((parts.length == 3) && (parts[1].equals("gallery_tabs"))) { doGalleryTabs(req, res, session, parts[2]); } // recognize nav login else if ((parts.length == 3) && (parts[1].equals("nav_login"))) { doNavLogin(req, res, session, parts[2]); } // recognize nav login for the gallery else if ((parts.length == 3) && (parts[1].equals("nav_login_gallery"))) { doNavLoginGallery(req, res, session, parts[2]); } // recognize presence else if ((parts.length >= 3) && (parts[1].equals("presence"))) { doPresence(req, res, session, parts[2], req.getContextPath() + req.getServletPath() + Web.makePath(parts, 1, 3), Web.makePath( parts, 3, parts.length)); } // recognize help else if ((parts.length >= 2) && (parts[1].equals("help"))) { doHelp(req, res, session, req.getContextPath() + req.getServletPath() + Web.makePath(parts, 1, 2), Web.makePath(parts, 2, parts.length)); } // recognize and dispatch the 'login' option else if ((parts.length == 2) && (parts[1].equals("relogin"))) { // Note: here we send a null path, meaning we will NOT set it as // a possible return path // we expect we are in the middle of a login screen processing, // and it's already set (user login button is "ulogin") -ggolden doLogin(req, res, session, null, false); } // recognize and dispatch the 'login' option else if ((parts.length == 2) && (parts[1].equals("login"))) { doLogin(req, res, session, "", false); } // recognize and dispatch the 'login' options else if ((parts.length == 2) && ((parts[1].equals("xlogin")))) { doLogin(req, res, session, "", true); } // recognize and dispatch the 'login' option for gallery else if ((parts.length == 2) && (parts[1].equals("login_gallery"))) { doLogin(req, res, session, "/gallery", false); } // recognize and dispatch the 'logout' option else if ((parts.length == 2) && (parts[1].equals("logout"))) { doLogout(req, res, session, null); } // recognize and dispatch the 'logout' option for gallery else if ((parts.length == 2) && (parts[1].equals("logout_gallery"))) { doLogout(req, res, session, "/gallery"); } // recognize error done else if ((parts.length >= 2) && (parts[1].equals("error-reported"))) { doErrorDone(req, res); } // handle an unrecognized request else { doError(req, res, session, 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 (!resetDone) { portalService.setResetState(null); } } /** * Title frames were no longer used in 2.3 and are not supported in 2.4 so * these methods are made private to notify derived classes. they can be * removed for 2.5 - csev */ protected void doTitle(HttpServletRequest req, HttpServletResponse res, Session session, String placementId, String toolContextPath, String toolPathInfo) throws ToolException, IOException { // find the tool from some site ToolConfiguration siteTool = SiteService.findTool(placementId); if (siteTool == null) { doError(req, res, session, ERROR_WORKSITE); return; } // find the tool registered for this ActiveTool tool = ActiveToolManager.getActiveTool(siteTool.getToolId()); if (tool == null) { doError(req, res, session, ERROR_WORKSITE); return; } // don't check permissions when just displaying the title... // // permission check - visit the site (unless the tool is configured // to bypass) // if (tool.getAccessSecurity() == Tool.AccessSecurity.PORTAL) // { // Site site = null; // try // { // site = SiteService.getSiteVisit(siteTool.getSiteId()); // } // catch (IdUnusedException e) // { // doError(req, res, session, ERROR_WORKSITE); // return; // } // catch (PermissionException e) // { // // if not logged in, give them a chance // if (session.getUserId() == null) // { // doLogin(req, res, session, URLUtils.getSafePathInfo(req), false); // } // else // { // doError(req, res, session, ERROR_WORKSITE); // } // return; // } // } includeTitle(tool, req, res, siteTool, siteTool.getSkin(), toolContextPath, toolPathInfo); } /** * Output the content of the title frame for a tool. */ protected void includeTitle(ActiveTool tool, HttpServletRequest req, HttpServletResponse res, ToolConfiguration placement, String skin, String toolContextPath, String toolPathInfo) throws IOException { // TODO: After 2.3 and the background document is modified - this may no // longer be needed // as the title is simply in the background document res.setContentType("text/html; charset=UTF-8"); 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"); if (skin == null || skin.length() == 0) skin = ServerConfigurationService.getString("skin.default"); String skinRepo = ServerConfigurationService.getString("skin.repo"); // the title to display in the title frame String toolTitle = Web.escapeHtml(placement.getTitle()); // for the reset button String resetActionUrl = toolContextPath + "?reset=true"; boolean resetToolNow = "true".equals(req.getParameter("reset")); boolean showResetButton = !"false".equals(placement.getConfig().getProperty( TOOLCONFIG_SHOW_RESET_BUTTON)); // 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( TOOLCONFIG_SHOW_HELP_BUTTON)); boolean showHelpButton = helpEnabledGlobally && helpEnabledInTool; String helpActionUrl = ""; if (showHelpButton) { String helpDocId = placement.getConfig().getProperty( TOOLCONFIG_HELP_DOCUMENT_ID); String helpDocUrl = placement.getConfig().getProperty( TOOLCONFIG_HELP_DOCUMENT_URL); if (helpDocUrl != null && helpDocUrl.length() > 0) { helpActionUrl = helpDocUrl; } else { if (helpDocId == null || helpDocId.length() == 0) { helpDocId = tool.getId(); } helpActionUrl = ServerConfigurationService.getHelpUrl(helpDocId); } } PrintWriter out = res.getWriter(); final String headHtml = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" + "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">\n" + " <head>\n" + " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n" + " <link href=\"" + skinRepo + "/tool_base.css\" type=\"text/css\" rel=\"stylesheet\" media=\"all\" />\n" + " <link href=\"" + skinRepo + "/" + skin + "/tool.css\" type=\"text/css\" rel=\"stylesheet\" media=\"all\" />\n" + " <meta http-equiv=\"Content-Style-Type\" content=\"text/css\" />\n" + " <script type=\"text/javascript\" src=\"" + getScriptPath() + "headscripts.js\"></script>\n" + " <title>" + toolTitle + "</title>\n" + " </head>\n" + " <body>\n"; final String tailHtml = "</body></html>\n"; out.write(headHtml); out.write("<div class=\"portletTitle\">\n"); out.write("\t<div class=\"title\">\n"); if (showResetButton) { out.write("\t\t<a href=\"" + resetActionUrl + "\" title=\"" + Web.escapeHtml(rb.getString("sit_reset")) + "\"><img src=\"/library/image/transparent.gif\" alt=\"" + Web.escapeHtml(rb.getString("sit_reset")) + "\" border=\"1\" /></a>"); } out.write("<h2>" + toolTitle + "\n" + "\t</h2></div>\n"); out.write("\t<div class=\"action\">\n"); if (showHelpButton) { out.write(makeHelpButton(helpActionUrl)); } out.write("\t</div>\n"); out.write("</div>\n"); if (resetToolNow) { // cause main tool frame to be reset // clear the session data associated with the tool - should reset // the tool Session s = SessionManager.getCurrentSession(); ToolSession ts = s.getToolSession(placement.getId()); ts.clearAttributes(); // redirect the main tool frame back to the initial tool URL. String mainFrameId = Web.escapeJavascript("Main" + placement.getId()); String mainFrameUrl = ServerConfigurationService.getToolUrl() + "/" + Web.escapeUrl(placement.getId()) + "?panel=Main"; out.write("<script type=\"text/javascript\">\n"); out.write("try\n"); out.write("{\n"); out .write(" if (parent." + mainFrameId + ".location.toString().length > 1)\n"); out.write(" {\n"); out .write(" parent." + mainFrameId + ".location = '" + mainFrameUrl + "';\n"); out.write(" }\n"); out.write("}\n"); out.write("catch (e1)\n"); out.write("{\n"); out.write(" try\n"); out.write(" {\n"); out.write(" if (parent.parent." + mainFrameId + ".location.toString().length > 1)\n"); out.write(" {\n"); out.write(" parent.parent." + mainFrameId + ".location = '" + mainFrameUrl + "';\n"); out.write(" }\n"); out.write(" }\n"); out.write(" catch (e2)\n"); out.write(" {\n"); out.write(" }\n"); out.write("}\n"); out.write("</script>\n"); } out.write(tailHtml); } private String makeHelpButton(String helpActionUrl) { return ("\t\t<a accesskey=\"h\"" + " href=\"" + helpActionUrl + "\" " + " title=\"" + Web.escapeHtml(rb.getString("sit_help")) + "\" " + " target=\"_blank\" " + " onclick=\"openWindow('" + helpActionUrl + "', 'Help'" + ", 'resizable=yes,toolbar=no,scrollbars=yes,menubar=yes,width=800,height=600'); return false\">" + "<img src=\"/library/image/transparent.gif\"" + " alt=\"" + Web.escapeHtml(rb.getString("sit_help")) + "\"" + " border=\"0\" /></a>\n"); } protected 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 session.setAttribute(Tool.HELPER_DONE_URL, Web.returnUrl(req, returnPath)); } 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 = (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 */ protected void doLogout(HttpServletRequest req, HttpServletResponse res, Session session, String returnPath) throws ToolException { // where to go after if (returnPath == null) { // if no path, use the configured logged out URL String loggedOutUrl = ServerConfigurationService.getLoggedOutUrl(); session.setAttribute(Tool.HELPER_DONE_URL, loggedOutUrl); } else { // if we have a path, use a return based on the request and this // path // Note: this is currently used only as "/gallery" // - we should really add a // ServerConfigurationService.getGalleryLoggedOutUrl() // and change the returnPath to a normal/gallery indicator -ggolden String loggedOutUrl = Web.returnUrl(req, 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"); } protected void doNavLogin(HttpServletRequest req, HttpServletResponse res, Session session, String siteId) throws IOException { // start the response PrintWriter out = startResponse(res, "Login", null, false); includeLogo(out, req, session, siteId); out.println("<div class=\"divColor\" id=\"tabBottom\"><br /></div></div>"); // end the response endResponse(out); } protected void doNavLoginGallery(HttpServletRequest req, HttpServletResponse res, Session session, String siteId) throws IOException { // start the response PrintWriter out = startResponse(res, "Login", null, false); includeGalleryLogin(out, req, session, siteId); out.println("<div class=\"divColor\" id=\"tabBottom\"><br /></div></div>"); // end the response endResponse(out); } protected void doPage(HttpServletRequest req, HttpServletResponse res, Session session, String pageId, String toolContextPath) throws ToolException, IOException { // find the page from some site SitePage page = SiteService.findPage(pageId); if (page == null) { doError(req, res, session, ERROR_WORKSITE); return; } // permission check - visit the site Site site = null; try { site = SiteService.getSiteVisit(page.getSiteId()); } catch (IdUnusedException e) { doError(req, res, session, ERROR_WORKSITE); return; } catch (PermissionException e) { // if not logged in, give them a chance if (session.getUserId() == null) { doLogin(req, res, session, URLUtils.getSafePathInfo(req), false); } else { doError(req, res, session, ERROR_WORKSITE); } return; } // form a context sensitive title String title = ServerConfigurationService.getString("ui.service","Sakai") + " : " + site.getTitle() + " : " + page.getTitle(); // start the response PrintWriter out = startResponse(res, title, page.getSkin(), true); // div to wrap the works String siteType = calcSiteType(site.getId()); out.println("<div id=\"container\"" + ((siteType != null) ? " class=\"" + siteType + "\"" : "") + ">"); includePage(req, res, page, toolContextPath, "contentFull"); out.println("</div>"); // end the response endResponse(out); } /** * 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 { try { basicAuth.doLogin(req); // get the Sakai session Session session = SessionManager.getCurrentSession(); // recognize what to do from the path String option = URLUtils.getSafePathInfo(req); // 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("/"); // recognize and dispatch the 'tool' option: [1] = "tool", [2] = // placement id (of a site's tool placement), rest for the tool if ((parts.length > 2) && (parts[1].equals("tool"))) { doTool(req, res, session, parts[2], req.getContextPath() + req.getServletPath() + Web.makePath(parts, 1, 3), Web.makePath( parts, 3, parts.length)); } else if (enableDirect && (parts.length > 2) && (parts[1].equals("directtool"))) { // Resolve the placements of the form // /portal/tool/sakai.resources?sakai.site=~csev String toolPlacement = getPlacement(req, res, session, parts[2], false); if (toolPlacement == null) { return; } parts[2] = toolPlacement; doDirectTool(req, res, session, parts[2], req.getContextPath() + req.getServletPath() + Web.makePath(parts, 1, 3), Web.makePath( parts, 3, parts.length)); } /** * Title frames were no longer used in 2.3 and are not supported in * 2.4 so we emit a WARN message here to help people with derived * classes figure out the new way. */ // TODO: Remove after 2.4 else if ((parts.length > 2) && (parts[1].equals("title"))) { doTitle(req, res, session, parts[2], req.getContextPath() + req.getServletPath() + Web.makePath(parts, 1, 3), Web.makePath( parts, 3, parts.length)); } // recognize and dispatch the 'login' options else if ((parts.length == 2) && ((parts[1].equals("login") || (parts[1].equals("xlogin")) || (parts[1] .equals("relogin"))))) { postLogin(req, res, session, parts[1]); } // recognize help else if ((parts.length >= 2) && (parts[1].equals("help"))) { doHelp(req, res, session, req.getContextPath() + req.getServletPath() + Web.makePath(parts, 1, 2), Web.makePath(parts, 2, parts.length)); } // recognize error feedback else if ((parts.length >= 2) && (parts[1].equals("error-report"))) { doErrorReport(req, res); } // handle an unrecognized request else { doError(req, res, session, ERROR_SITE); } } catch (Throwable t) { doThrowableError(req, res, t); } } protected void doPresence(HttpServletRequest req, HttpServletResponse res, Session session, String siteId, String toolContextPath, String toolPathInfo) throws ToolException, IOException { // permission check - visit the site Site site = null; try { site = SiteService.getSiteVisit(siteId); } catch (IdUnusedException e) { doError(req, res, session, ERROR_WORKSITE); return; } catch (PermissionException e) { // if not logged in, give them a chance if (session.getUserId() == null) { doLogin(req, res, session, URLUtils.getSafePathInfo(req), false); } else { doError(req, res, session, ERROR_WORKSITE); } return; } // get the skin for the site String skin = site.getSkin(); // find the tool registered for this ActiveTool tool = ActiveToolManager.getActiveTool("sakai.presence"); if (tool == null) { doError(req, res, session, ERROR_WORKSITE); return; } // form a placement based on the site and the fact that this is that // site's presence... // Note: the placement is transient, but will always have the same id // and context based on the siteId org.sakaiproject.util.Placement placement = new org.sakaiproject.util.Placement( siteId + "-presence", tool.getId(), tool, null, siteId, null); forwardTool(tool, req, res, placement, skin, toolContextPath, toolPathInfo); } protected void doHelp(HttpServletRequest req, HttpServletResponse res, Session session, String toolContextPath, String toolPathInfo) throws ToolException, IOException { // permission check - none // get the detault skin String skin = ServerConfigurationService.getString("skin.default"); // find the tool registered for this ActiveTool tool = ActiveToolManager.getActiveTool("sakai.help"); if (tool == null) { doError(req, res, session, ERROR_WORKSITE); return; } // form a placement based on ... help TODO: is this enough? // Note: the placement is transient, but will always have the same id // and (null) context org.sakaiproject.util.Placement placement = new org.sakaiproject.util.Placement( "help", tool.getId(), tool, null, null, null); forwardTool(tool, req, res, placement, skin, toolContextPath, toolPathInfo); } protected void doErrorReport(HttpServletRequest req, HttpServletResponse res) throws ToolException, IOException { setupForward(req, res, null, null); ErrorReporter err = new ErrorReporter(); err.postResponse(req, res); } protected void doErrorDone(HttpServletRequest req, HttpServletResponse res) throws ToolException, IOException { setupForward(req, res, null, null); ErrorReporter err = new ErrorReporter(); err.thanksResponse(req, res); } protected void doSite(HttpServletRequest req, HttpServletResponse res, Session session, String siteId, String pageId, String toolContextPath) throws ToolException, IOException { // default site if not set if (siteId == null) { if (session.getUserId() == null) { siteId = ServerConfigurationService.getGatewaySiteId(); } else { siteId = SiteService.getUserSiteId(session.getUserId()); } } // if no page id, see if there was a last page visited for this site if (pageId == null) { pageId = (String) session.getAttribute(ATTR_SITE_PAGE + siteId); } // find the site, for visiting Site site = null; try { site = getSiteVisit(siteId); } catch (IdUnusedException e) { doError(req, res, session, ERROR_SITE); return; } catch (PermissionException e) { // if not logged in, give them a chance if (session.getUserId() == null) { doLogin(req, res, session, URLUtils.getSafePathInfo(req), false); } else { doError(req, res, session, ERROR_SITE); } return; } // find the page, or use the first page if pageId not found SitePage page = site.getPage(pageId); if (page == null) { List pages = site.getOrderedPages(); if (!pages.isEmpty()) { page = (SitePage) pages.get(0); } } if (page == null) { doError(req, res, session, ERROR_SITE); return; } // store the last page visited session.setAttribute(ATTR_SITE_PAGE + siteId, page.getId()); // form a context sensitive title String title = ServerConfigurationService.getString("ui.service","Sakai") + " : " + site.getTitle() + " : " + page.getTitle(); // start the response PrintWriter out = startResponse(res, title, site.getSkin(), true); // the 'full' top area includeSiteNav(out, req, session, siteId); String siteType = calcSiteType(siteId); out.println("<div id=\"container\"" + ((siteType != null) ? " class=\"" + siteType + "\"" : "") + ">"); includeWorksite(req, res, session, site, page, toolContextPath, "site"); out.println("<div>"); includeBottom(out); // end the response endResponse(out); } // 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 pllacement, 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. protected 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 // find the site, for visiting // Sites like the !gateway site allow visits by anonymous Site site = null; try { site = SiteService.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, URLUtils.getSafePathInfo(req) + "?sakai.site=" + res.encodeURL(siteId), 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(); } } protected void doSiteTabs(HttpServletRequest req, HttpServletResponse res, Session session, String siteId) throws IOException { // get the site's skin String skin = getSiteSkin(siteId); // start the response PrintWriter out = startResponse(res, "Site Navigation", skin, false); includeLogo(out, req, session, siteId); includeTabs(out, req, session, siteId, "site", false); // end the response endResponse(out); } /** * Do direct tool, takes the url, stored the destination and the target * iframe in the session constructs and outer url and when a request comes * in that matches the stored iframe it ejects the destination address * * @param req * @param res * @param session * @param placementId * @param toolContextPath * @param toolPathInfo * @param placementId * @throws ToolException * @throws IOException */ protected void doDirectTool(HttpServletRequest req, HttpServletResponse res, Session session, String placementId, String toolContextPath, String toolPathInfo) throws ToolException, IOException { if (redirectIfLoggedOut(res)) return; // find the tool from some site ToolConfiguration siteTool = SiteService.findTool(placementId); if (siteTool == null) { doError(req, res, session, ERROR_WORKSITE); return; } // Reset the tool state if requested if (portalService.isResetRequested(req)) { Session s = SessionManager.getCurrentSession(); ToolSession ts = s.getToolSession(placementId); ts.clearAttributes(); } // find the tool registered for this ActiveTool tool = ActiveToolManager.getActiveTool(siteTool.getToolId()); if (tool == null) { doError(req, res, session, ERROR_WORKSITE); return; } // permission check - visit the site (unless the tool is configured to // bypass) if (tool.getAccessSecurity() == Tool.AccessSecurity.PORTAL) { Site site = null; try { site = SiteService.getSiteVisit(siteTool.getSiteId()); } catch (IdUnusedException e) { doError(req, res, session, ERROR_WORKSITE); return; } catch (PermissionException e) { // if not logged in, give them a chance if (session.getUserId() == null) { // let the tool do the the work (forward) StoredState ss = portalService.newStoredState("directtool", "tool"); ss.setRequest(req); ss.setPlacement(siteTool); ss.setToolContextPath(toolContextPath); ss.setToolPathInfo(toolPathInfo); ss.setSkin(siteTool.getSkin()); portalService.setStoredState(ss); doLogin(req, res, session, getPortalPageUrl(siteTool), false); } else { doError(req, res, session, ERROR_WORKSITE); } return; } } // let the tool do the the work (forward) StoredState ss = portalService.newStoredState("directtool", "tool"); ss.setRequest(req); ss.setPlacement(siteTool); ss.setToolContextPath(toolContextPath); ss.setToolPathInfo(toolPathInfo); ss.setSkin(siteTool.getSkin()); portalService.setStoredState(ss); forwardPortal(tool, req, res, siteTool, siteTool.getSkin(), toolContextPath, toolPathInfo); } protected void doTool(HttpServletRequest req, HttpServletResponse res, Session session, String placementId, String toolContextPath, String toolPathInfo) throws ToolException, IOException { if (redirectIfLoggedOut(res)) return; // find the tool from some site ToolConfiguration siteTool = SiteService.findTool(placementId); if (siteTool == null) { doError(req, res, session, ERROR_WORKSITE); return; } // Reset the tool state if requested if (portalService.isResetRequested(req)) { Session s = SessionManager.getCurrentSession(); ToolSession ts = s.getToolSession(placementId); ts.clearAttributes(); } // find the tool registered for this ActiveTool tool = ActiveToolManager.getActiveTool(siteTool.getToolId()); if (tool == null) { doError(req, res, session, ERROR_WORKSITE); return; } // permission check - visit the site (unless the tool is configured to // bypass) if (tool.getAccessSecurity() == Tool.AccessSecurity.PORTAL) { try { SiteService.getSiteVisit(siteTool.getSiteId()); } catch (IdUnusedException e) { doError(req, res, session, ERROR_WORKSITE); return; } catch (PermissionException e) { // if not logged in, give them a chance if (session.getUserId() == null) { doLogin(req, res, session, URLUtils.getSafePathInfo(req), false); } else { doError(req, res, session, ERROR_WORKSITE); } return; } } forwardTool(tool, req, res, siteTool, siteTool.getSkin(), toolContextPath, toolPathInfo); } protected void setupForward(HttpServletRequest req, HttpServletResponse res, Placement p, String skin) throws ToolException { // 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; String headJs = "<script type=\"text/javascript\" src=\"/library/js/headscripts.js\"></script>\n"; String head = headCss + headJs; StringBuilder bodyonload = new StringBuilder(); if (p != null) { String element = Web.escapeJavascript("Main" + p.getId()); bodyonload.append("setMainFrameHeight('" + element + "');"); } bodyonload.append("setFocus(focus_path);"); // to force all non-legacy tools to use the standard css // to help in transition (needs corresponding entry in properties) // if // ("true".equals(ServerConfigurationService.getString("skin.force"))) // { // headJs = headJs + headCss; // } req.setAttribute("sakai.html.head", head); req.setAttribute("sakai.html.head.css", headCss); req.setAttribute("sakai.html.head.css.base", headCssToolBase); req.setAttribute("sakai.html.head.css.skin", headCssToolSkin); req.setAttribute("sakai.html.head.js", headJs); req.setAttribute("sakai.html.body.onload", bodyonload.toString()); } /** * Forward to the tool - but first setup JavaScript/CSS etc that the tool * will render */ protected 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 { 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 // target portalService.setStoredState(null); } } else { setupForward(req, res, p, skin); req.setAttribute(ToolURL.MANAGER, new ToolURLManagerImpl(res)); tool.forward(req, res, p, toolContextPath, toolPathInfo); } } protected void forwardPortal(ActiveTool tool, HttpServletRequest req, HttpServletResponse res, ToolConfiguration p, String skin, String toolContextPath, String toolPathInfo) throws ToolException, IOException { // 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 = "/portal" + getPortalPageUrl(p); res.sendRedirect(portalPlacementUrl); return; } protected String getPortalPageUrl(ToolConfiguration p) { return "/site/" + p.getSiteId() + "/page/" + p.getPageId(); } protected void doWorksite(HttpServletRequest req, HttpServletResponse res, Session session, String siteId, String pageId, String toolContextPath) throws ToolException, IOException { // if no page id, see if there was a last page visited for this site if (pageId == null) { pageId = (String) session.getAttribute(ATTR_SITE_PAGE + siteId); } // find the site, for visiting Site site = null; try { site = getSiteVisit(siteId); } catch (IdUnusedException e) { doError(req, res, session, ERROR_WORKSITE); return; } catch (PermissionException e) { // if not logged in, give them a chance if (session.getUserId() == null) { doLogin(req, res, session, URLUtils.getSafePathInfo(req), false); } else { doError(req, res, session, ERROR_WORKSITE); } return; } // find the page, or use the first page if pageId not found SitePage page = site.getPage(pageId); if (page == null) { List pages = site.getOrderedPages(); if (!pages.isEmpty()) { page = (SitePage) pages.get(0); } } if (page == null) { doError(req, res, session, ERROR_WORKSITE); return; } // store the last page visited session.setAttribute(ATTR_SITE_PAGE + siteId, page.getId()); // form a context sensitive title String title = ServerConfigurationService.getString("ui.service","Sakai") + " : " + site.getTitle() + " : " + page.getTitle(); // start the response PrintWriter out = startResponse(res, title, site.getSkin(), true); String siteType = calcSiteType(siteId); out.println("<div id=\"container\"" + ((siteType != null) ? " class=\"" + siteType + "\"" : "") + ">"); includeWorksite(req, res, session, site, page, toolContextPath, "worksite"); out.println("<div>"); // end the response endResponse(out); } protected void endResponse(PrintWriter out) { out.println("</body></html>"); } protected String getScriptPath() { String libPath = "/library"; return libPath + "/js/"; } /** * Access the Servlet's information display. * * @return servlet information. */ public String getServletInfo() { return "Sakai Charon Portal"; } protected void includeBottom(PrintWriter out) { 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"); out.println("<div id=\"footer\">"); out.println(" <div class=\"footerExtNav\" align=\"center\">"); out.println(" |"); if ((bottomNav != null) && (bottomNav.length > 0)) { for (int i = 0; i < bottomNav.length; i++) { out.println(" " + bottomNav[i] + " | "); } } out.println(" </div>"); out.println(" <div id=\"footerInfo\">"); if ((poweredByUrl != null) && (poweredByImage != null) && (poweredByAltText != null) && (poweredByUrl.length == poweredByImage.length) && (poweredByUrl.length == poweredByAltText.length)) { for (int i = 0; i < poweredByUrl.length; i++) { out.println(" <span class=\"skip\">" + Web.escapeHtml(rb.getString("site_newwindow")) + "</span> <a href=\"" + poweredByUrl[i] + "\" target=\"_blank\">" + "<img border=\"0\" src=\"" + poweredByImage[i] + "\" alt=\"" + poweredByAltText[i] + "\" /></a>"); } } else { out .println(" <span class=\"skip\">" + Web.escapeHtml(rb.getString("site_newwindow")) + "</span><a href=\"http://sakaiproject.org\" target=\"_blank\">" + "<img border=\"0\" src=\"/library/image/sakai_powered.gif\" alt=\"Powered by Sakai\" /></a>"); } out.println(" </div>"); out.println(" <div class=\"sakaiCopyrightInfo\">" + copyright + "<br />"); out.println(" " + service + " - " + serviceVersion + " - Sakai " + sakaiVersion + " (kernel: " + kernelVersion + ") - Server \"" + server + "\"</div>"); out.println(" </div>"); out.println("</div>"); out.println("</div>"); out.println("</div>"); out.println("</div>"); } protected void includeGalleryLogin(PrintWriter out, HttpServletRequest req, Session session, String siteId) throws IOException { out.println("<div class=\"siteNavBlock\">"); out .println("<table class=\"mast-head\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" width=\"100%\">"); out.println(" <tr>"); out.println(" <td class=\"right mast-head-r right\">"); this.includeLogin(out, req, session); out.println(" </td>"); out.println(" </tr>"); out.println("</table>"); } protected void includeGalleryNav(PrintWriter out, HttpServletRequest req, Session session, String siteId) { boolean loggedIn = session.getUserId() != null; // outer blocks and jump-to links out.println(" <div id=\"portalOuterContainer\">"); out.println(" <div id=\"portalContainer\">"); out.println("<div id=\"skipNav\">"); String accessibilityURL = ServerConfigurationService .getString("accessibility.url"); if (accessibilityURL != null && !accessibilityURL.equals("")) { out.println("<a href=\"" + accessibilityURL + "\" class=\"skip\" title=\"" + Web.escapeHtml(rb.getString("sit_accessibility")) + "\" accesskey=\"0\">" + Web.escapeHtml(rb.getString("sit_accessibility")) + "</a>"); } out.println(" <a href=\"#tocontent\" class=\"skip\" title=\"" + Web.escapeHtml(rb.getString("sit_jumpcontent")) + "\" accesskey=\"c\">" + Web.escapeHtml(rb.getString("sit_jumpcontent")) + "</a>"); out.println(" <a href=\"#totoolmenu\" class=\"skip\" title=\"" + Web.escapeHtml(rb.getString("sit_jumptools")) + "\" accesskey=\"l\">" + Web.escapeHtml(rb.getString("sit_jumptools")) + "</a>"); out.println(" <a href=\"#sitetabs\" class=\"skip\" title=\"" + Web.escapeHtml(rb.getString("sit_jumpworksite")) + "\" accesskey=\"w\">" + Web.escapeHtml(rb.getString("sit_jumpworksite")) + "</a>"); out.println("</div>"); if (loggedIn) { out.println("<div id=\"headerMax\">"); } else { out.println("<div id=\"headerMin\">"); } try { if (loggedIn) { includeTabs(out, req, session, siteId, "gallery", false); } else { includeGalleryLogin(out, req, session, siteId); out .println("<div class=\"divColor\" id=\"tabBottom\"><br /></div></div>"); } } catch (Exception any) { } out.println("</div>"); } protected void includeLogo(PrintWriter out, HttpServletRequest req, Session session, String siteId) throws IOException { String skin = getSiteSkin(siteId); String skinRepo = ServerConfigurationService.getString("skin.repo"); String logo = skinRepo + "/" + skin + "/images/logo_inst.gif"; String banner = skinRepo + "/" + skin + "/images/banner_inst.gif"; String siteType = calcSiteType(siteId); String cssClass = (siteType != null) ? siteType : "undeterminedSiteType"; out.println("<div id=\"siteNavWrapper\" class=\"" + cssClass + "\">"); out.println("<div id=\"mastHead\">"); out.println(" <div id=\"mastLogo\">"); out.println(" <img title=\"Logo\" alt=\"Logo\" src=\"" + logo + "\" />"); out.println(" </div>"); out.println(" <div id=\"mastBanner\">"); out.println(" <img title=\"Banner\" alt=\"Banner\" src=\"" + banner + "\" />"); out.println(" </div>"); out.println(" <div id=\"mastLogin\">"); includeLogin(out, req, session); out.println(" </div>"); out.println("</div>"); } protected void includeLogin(PrintWriter out, HttpServletRequest req, Session session) { // 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; // 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 = ServerConfigurationService.getBoolean("top.login", true); boolean containerLogin = ServerConfigurationService.getBoolean("container.login", false); 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 = rb.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"; // check for a logout text override message = StringUtils.trimToNull(ServerConfigurationService .getString("logout.text")); if (message == null) message = rb.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; } // put out the links version if (!topLogin) { out.println("<div id=\"loginLinks\">"); out.println(" <a href=\"" + logInOutUrl + "\" target=\"_parent\" title=\"" + message + "\">" + ((image1 == null) ? message : "<img src=\"" + image1 + "\"/>") + "</a>"); if (logInOutUrl2 != null) { out.println(" <a href=\"" + logInOutUrl2 + "\" target=\"_parent\" title=\"" + message2 + "\">" + ((image2 == null) ? message2 : "<img alt=\"" + message2 + "\" src=\"" + image2 + "\"/>") + "</a>"); } out.println("</div>"); } // else put out the fields that will send to the login interface else { String eidWording = null; String pwWording = null; eidWording = StringUtils.trimToNull(rb.getString("log.userid")); pwWording = StringUtils.trimToNull(rb.getString("log.pass")); if (eidWording == null) eidWording = "eid"; if (pwWording == null) pwWording = "pw"; String loginWording = rb.getString("log.login"); out .println("<form id=\"loginForm\" method=\"post\" action=\"" + ServerConfigurationService.getString("portalPath") + "/xlogin\" enctype=\"application/x-www-form-urlencoded\" target=\"_parent\">"); out.println("<label for=\"eid\">" + eidWording + "</label><input name=\"eid\" id=\"eid\" type=\"text\" />"); out.println("<label for=\"pw\">" + pwWording + "</label><input name=\"pw\" type=\"password\" id=\"pw\" />"); out.println("<input name=\"submit\" type=\"submit\" id=\"submit\" value=\"" + loginWording + "\" /> </form>"); out.println("<script type=\"text/javascript\">"); out.println("document.forms[0].eid.focus();"); out.println("</script>"); // setup for the redirect after login session.setAttribute(Tool.HELPER_DONE_URL, ServerConfigurationService .getPortalUrl()); } } protected void includePage(HttpServletRequest req, HttpServletResponse res, SitePage page, String toolContextPath, String wrapperClass) throws IOException { PrintWriter out = res.getWriter(); // divs to wrap the tools // divs to wrap the tools out.println("<div id=\"" + wrapperClass + "\">"); // get the tools on this first column of page if (page.getLayout() == SitePage.LAYOUT_DOUBLE_COL) { out.println("<div id=\"col1of2\">"); } else { out.println("<div id=\"col1\">"); } Site site = null; try { site = SiteService.getSite(page.getSiteId()); } catch (Exception ignoreMe) { // Non fatal - just assume null if (M_log.isTraceEnabled()) M_log.trace("includePage unable to find site for page " + page.getId()); } List tools = page.getTools(0); for (Iterator i = tools.iterator(); i.hasNext();) { ToolConfiguration placement = (ToolConfiguration) i.next(); if (site != null) { boolean thisTool = allowTool(site, placement); // System.out.println(" Allow Tool Display -" + // placement.getTitle() + " retval = " + thisTool); if (!thisTool) continue; // Skip this tool if not allowed } // for this tool invocation, form the servlet context and path info String contextPath = ServerConfigurationService.getToolUrl() + "/" + Web.escapeUrl(placement.getId()); String pathInfo = null; // invoke the tool includeTool(req, res, placement); } out.println("</div>"); // do the second column if needed if (page.getLayout() == SitePage.LAYOUT_DOUBLE_COL) { out.println("<div id=\"col2of2\">"); tools = page.getTools(1); for (Iterator i = tools.iterator(); i.hasNext();) { ToolConfiguration placement = (ToolConfiguration) i.next(); // for this tool invocation, form the servlet context and path // info String contextPath = ServerConfigurationService.getToolUrl() + "/" + Web.escapeUrl(placement.getId()); String pathInfo = null; // invoke the tool includeTool(req, res, placement); } out.println("</div>"); } out.println("</div>"); } protected boolean allowTool(Site site, Placement placement) { return toolHelper.allowTool(site, placement); } protected void includePageNav(HttpServletRequest req, HttpServletResponse res, Session session, Site site, SitePage page, String toolContextPath, String portalPrefix) throws IOException { PrintWriter out = res.getWriter(); // If we have turned on auto-state reset on navigation, we generate the // "site-reset" "worksite-reset" and "gallery-reset" urls if ("true".equalsIgnoreCase(ServerConfigurationService.getString(CONFIG_AUTO_RESET))) { portalPrefix = portalPrefix + "-reset"; } String pageUrl = Web.returnUrl(req, "/" + portalPrefix + "/" + Web.escapeUrl(getSiteEffectiveId(site)) + "/page/"); String pagePopupUrl = Web.returnUrl(req, "/page/"); boolean showPresence = ServerConfigurationService.getBoolean( "display.users.present", true); boolean showHelp = ServerConfigurationService.getBoolean("display.help.menu", true); boolean loggedIn = session.getUserId() != null; String iconUrl = site.getIconUrlFull(); boolean published = site.isPublished(); String type = site.getType(); out.println("<div class=\"divColor\" id=\"toolMenuWrap\">"); out.println(" <div id=\"worksiteLogo\">"); if (!published) { out.println("<p id=\"siteStatus\">" + "unpublished site" + "</p>"); } if (type != null) { if (type.equals("project")) { out.println("<p id=\"siteType\">" + type + "</p>"); } } if (iconUrl != null) { out.println(" <img src=\"" + iconUrl + "\" border=\"0\" />"); } out.println(" </div>"); // target of "jump to tools" link, header out.println(" <a id=\"totoolmenu\" class=\"skip\" name=\"totoolmenu\"></a>"); out.println(" <h1 class=\"skip\">" + Web.escapeHtml(rb.getString("sit_toolshead")) + "</h1>"); out.println(" <div id=\"toolMenu\">"); out.println(" <ul>"); // order the pages based on their tools and the tool order for the site // type List pages = site.getOrderedPages(); // gsilver - counter for tool accesskey attributes of <a> // int count = 0; for (Iterator i = pages.iterator(); i.hasNext();) { SitePage p = (SitePage) i.next(); // check if current user has permission to see page // will draw page button if it have permission to see at least one // tool List pTools = p.getTools(); Iterator iPt = pTools.iterator(); boolean allowPage = false; while (iPt.hasNext()) { ToolConfiguration placement = (ToolConfiguration) iPt.next(); boolean thisTool = allowTool(site, placement); if (thisTool) allowPage = true; // System.out.println(" Allow Tool -" + tool.getTitle() + " // retval = " + thisTool + " page=" + allowPage); } if (!allowPage) continue; boolean current = (p.getId().equals(page.getId()) && !p.isPopUp()); if (current) { out.print(" <li class=\"selectedTool\"><a "); } else { out.print(" <li><a "); } // removing accesskeys from tool menu // if (count < 10) // { // out.print("accesskey=\"" + count + "\" "); // } if (current) { out.print("class=\"selected\" "); } out.print("href=\""); if (current) { out.print("#"); } else if (p.isPopUp()) { out .print("javascript:;\" " + "onclick=\"window.open('" + pagePopupUrl + Web.escapeUrl(p.getId()) + "'" + ",'" + Web.escapeJavascript(p.getTitle()) + "','resizable=yes,toolbar=no,scrollbars=yes, width=800,height=600')"); } else { String pagerefUrl = pageUrl + Web.escapeUrl(p.getId()); out.print(pagerefUrl); } out.println("\"><span>" + Web.escapeHtml(p.getTitle()) + "</span></a></li>"); // count++; } if (showHelp) { String helpUrl = ServerConfigurationService.getHelpUrl(null); out.println(" <li>"); // help gets its own accesskey - 6 out .println(" <a accesskey=\"6\" href=\"" + helpUrl + "\" target=\"_blank\" " + "onclick=\"openWindow('" + helpUrl + "', 'Help', 'resizable=yes,toolbar=no,scrollbars=yes,menubar=yes,width=800,height=600'); return false\">" + "<span>" + rb.getString("sit_help") + "</span></a>"); out.println(" </li>"); } out.println(" </ul>"); out.println(" </div>"); if (showPresence && loggedIn) { String presenceUrl = Web.returnUrl(req, "/presence/" + Web.escapeUrl(site.getId())); out.println(" <div id=\"presenceWrapper\">"); out.println(" <div id=\"presenceTitle\">"); out.println(Web.escapeHtml(rb.getString("sit_presencetitle"))); out.println(" </div>"); out.println(" <iframe "); out.println(" name=\"presenceIframe\""); out.println(" id=\"presenceIframe\""); out.println(" title=\"" + Web.escapeHtml(rb.getString("sit_presenceiframetit")) + "\""); out.println(" frameborder=\"0\""); out.println(" marginwidth=\"0\""); out.println(" marginheight=\"0\""); out.println(" scrolling=\"auto\""); out.println(" src=\"" + presenceUrl + "\""); out.println(" >"); out.println(" </iframe>"); out.println(" </div>"); } out.println("</div>"); // target of "jump to content" link and header for content out.println(" <h1 class=\"skip\">" + Web.escapeHtml(rb.getString("sit_contentshead")) + "</h1>"); out.println(" <a id=\"tocontent\" class=\"skip\" name=\"tocontent\"></a>"); } protected void includeSiteNav(PrintWriter out, HttpServletRequest req, Session session, String siteId) { boolean loggedIn = session.getUserId() != null; // outer blocks and jump to links out.println(" <div id=\"portalOuterContainer\">"); out.println(" <div id=\"portalContainer\">"); out.println("<div id=\"skipNav\">"); String accessibilityURL = ServerConfigurationService .getString("accessibility.url"); if (accessibilityURL != null && !accessibilityURL.equals("")) { out.println("<a href=\"" + accessibilityURL + "\" class=\"skip\" title=\"" + Web.escapeHtml(rb.getString("sit_accessibility")) + "\" accesskey=\"0\">" + Web.escapeHtml(rb.getString("sit_accessibility")) + "</a>"); } out.println("<a href=\"#tocontent\" class=\"skip\" title=\"" + Web.escapeHtml(rb.getString("sit_jumpcontent")) + "\" accesskey=\"c\">" + Web.escapeHtml(rb.getString("sit_jumpcontent")) + "</a>"); out.println("<a href=\"#totoolmenu\" class=\"skip\" title=\"" + Web.escapeHtml(rb.getString("sit_jumptools")) + "\" accesskey=\"l\">" + Web.escapeHtml(rb.getString("sit_jumptools")) + "</a>"); out.println("<a href=\"#sitetabs\" class=\"skip\" title=\"" + Web.escapeHtml(rb.getString("sit_jumpworksite")) + "\" accesskey=\"w\">" + Web.escapeHtml(rb.getString("sit_jumpworksite")) + "</a>"); out.println("</div>"); if (loggedIn) { out.println("<div id=\"headerMax\">"); } else { out.println("<div id=\"headerMin\">"); } try { if (loggedIn) { includeLogo(out, req, session, siteId); includeTabs(out, req, session, siteId, "site", false); } else { includeLogo(out, req, session, siteId); out .println("<div class=\"divColor\" id=\"tabBottom\"><br /></div></div>"); } } catch (Exception any) { } out.println("</div>"); } protected void includeTabs(PrintWriter out, HttpServletRequest req, Session session, String siteId, String prefix, boolean addLogout) throws IOException { // for skinning String siteType = calcSiteType(siteId); // If we have turned on auto-state reset on navigation, we generate the // "site-reset" "worksite-reset" and "gallery-reset" urls if ("true".equalsIgnoreCase(ServerConfigurationService.getString(CONFIG_AUTO_RESET))) { prefix = prefix + "-reset"; } // is the current site the end user's My Workspace? // Note: the site id can match the user's id or eid String curUserId = session.getUserId(); String curUserEid = curUserId; if (siteId != null) { try { curUserEid = UserDirectoryService.getUserEid(curUserId); } catch (UserNotDefinedException e) { } } boolean curMyWorkspace = ((siteId == null) || (SiteService.isUserSite(siteId) && ((SiteService .getSiteUserId(siteId).equals(curUserId) || SiteService.getSiteUserId( siteId).equals(curUserEid))))); // if this is a My Workspace, it gets its own tab and should not be // considered in the other tab logic if (curMyWorkspace) siteId = null; // collect the user's sites List mySites = SiteService.getSites( org.sakaiproject.site.api.SiteService.SelectionType.ACCESS, null, null, null, org.sakaiproject.site.api.SiteService.SortType.TITLE_ASC, null); // collect the user's preferences int prefTabs = 4; List prefExclude = new Vector(); List prefOrder = new Vector(); if (session.getUserId() != null) { Preferences prefs = PreferencesService.getPreferences(session.getUserId()); ResourceProperties props = prefs.getProperties("sakai:portal:sitenav"); try { prefTabs = (int) props.getLongProperty("tabs"); } catch (Exception any) { } List l = props.getPropertyList("exclude"); if (l != null) { prefExclude = l; } l = props.getPropertyList("order"); if (l != null) { prefOrder = l; } } // the number of tabs to display int tabsToDisplay = prefTabs; // remove all in exclude from mySites mySites.removeAll(prefExclude); // re-order mySites to have order first, the rest later List ordered = new Vector(); for (Iterator i = prefOrder.iterator(); i.hasNext();) { String id = (String) i.next(); // find this site in the mySites list int pos = indexOf(id, mySites); if (pos != -1) { // move it from mySites to order Site s = (Site) mySites.get(pos); ordered.add(s); mySites.remove(pos); } } // pick up the rest of the sites ordered.addAll(mySites); mySites = ordered; // split into 2 lists - the first n, and the rest List moreSites = new Vector(); if (mySites.size() > tabsToDisplay) { int remove = mySites.size() - tabsToDisplay; for (int i = 0; i < remove; i++) { Site site = (Site) mySites.get(tabsToDisplay); // add to more unless it's the current site (it will get an // extra tag) if (!site.getId().equals(siteId)) { moreSites.add(site); } // remove from the display list mySites.remove(tabsToDisplay); } } // if more has just one, put it back on the main list if (moreSites.size() == 1) { mySites.add(moreSites.get(0)); moreSites.clear(); } // check if the current site is missing from the main list String extraTitle = null; if (siteId != null) { boolean extra = true; for (Iterator i = mySites.iterator(); i.hasNext();) { Site site = (Site) i.next(); if (site.getId().equals(siteId)) { extra = false; break; } } if (extra) { try { Site site = SiteService.getSite(siteId); extraTitle = site.getTitle(); } catch (IdUnusedException e) { // check for another user's myWorkspace by eid if (SiteService.isUserSite(siteId)) { String userEid = SiteService.getSiteUserId(siteId); try { String userId = UserDirectoryService.getUserId(userEid); Site site = SiteService.getSite(SiteService .getUserSiteId(userId)); extraTitle = site.getTitle(); } catch (UserNotDefinedException ee) { M_log.warn("includeTabs: cur site not found (not ~eid): " + siteId); } catch (IdUnusedException ee) { M_log .warn("includeTabs: cur site not found (assumed ~eid, didn't find site): " + siteId); } } else { M_log.warn("includeTabs: cur site not found: " + siteId); } } } } String cssClass = (siteType != null) ? "siteNavWrap " + siteType : "siteNavWrap"; out.println("<div class=\"" + cssClass + "\">"); out.println(" <div id=\"siteNav\">"); // out.println(" <tr>"); out.println(" <div id=\"linkNav\">"); // target for "jump to tabs" link and header out.println(" <a id=\"sitetabs\" class=\"skip\" name=\"sitetabs\"></a>"); out.println(" <h1 class=\"skip\">" + Web.escapeHtml(rb.getString("sit_worksiteshead")) + "</h1>"); out.println(" <ul id=\"siteLinkList\">"); // myWorkspace if (curMyWorkspace) { out.println(" <li class=\"selectedTab\"><a href=\"#\"><span>" + rb.getString("sit_mywor") + "</span></a></li>"); } else { String siteUrl = Web.serverUrl(req) + ServerConfigurationService.getString("portalPath") + "/" + prefix + "/" + Web.escapeUrl(getUserEidBasedSiteId(session.getUserId())); out.println(" <li><a href=\"" + siteUrl + "\" target=\"_parent\" title=\"" + Web.escapeHtml(rb.getString("sit_mywor")) + "\"><span>" + Web.escapeHtml(rb.getString("sit_mywor")) + "</span></a></li>"); } // first n tabs for (Iterator i = mySites.iterator(); i.hasNext();) { Site s = (Site) i.next(); if (s.getId().equals(siteId)) { out.println(" <li class=\"selectedTab\"><a href=\"#\"><span>" + Web.escapeHtml(s.getTitle()) + "</span></a></li>"); } else { String siteUrl = Web.serverUrl(req) + ServerConfigurationService.getString("portalPath") + "/" + prefix + "/" + Web.escapeUrl(getSiteEffectiveId(s)); out .println(" <li><a href=\"" + siteUrl + "\" target=\"_parent\" title=\"" + Web.escapeHtml(s.getTitle()) + " " + Web.escapeHtml(rb.getString("sit_worksite")) + "\"><span>" + Web.escapeHtml(s.getTitle()) + "</span></a></li>"); } } // current site, if not in the list of first n tabs if (extraTitle != null) { out.println(" <li class=\"selectedTab\"><a><span>" + Web.escapeHtml(extraTitle) + "</span></a></li>"); } out.println(" <li style=\"display:none;border-width:0\" class=\"fixTabsIE\">" + "<a href=\"javascript:void(0);\">#x20;</a></li>"); out.println(" </ul>"); out.println(" </div>"); // more dropdown if (moreSites.size() > 0) { out.println(" <div id=\"selectNav\"><span class=\"skip\">" + Web.escapeHtml(rb.getString("sit_selectmessage")) + "</span>"); out.println(" <select "); out .println(" onchange=\"if (this.options[this.selectedIndex].value != '')" + " { parent.location = this.options[this.selectedIndex].value; } else { this.selectedIndex = 0; }\">"); out.println(" <option value=\"\" selected=\"selected\">" + Web.escapeHtml(rb.getString("sit_more")) + "</option>"); for (Iterator i = moreSites.iterator(); i.hasNext();) { Site s = (Site) i.next(); String siteUrl = Web.serverUrl(req) + ServerConfigurationService.getString("portalPath") + "/" + prefix + "/" + getSiteEffectiveId(s); out.println(" <option title=\"" + Web.escapeHtml(s.getTitle()) + " " + Web.escapeHtml(rb.getString("sit_worksite")) + "\" value=\"" + siteUrl + "\">" + Web.escapeHtml(s.getTitle()) + "</option> "); } out.println(" </select>"); out.println(" </div>"); } if (addLogout) { String logoutUrl = Web.serverUrl(req) + ServerConfigurationService.getString("portalPath") + "/logout_gallery"; out.println("<div class=\"galleryLogin\">"); out.println(" <a href=\"" + logoutUrl + "\" target=\"_parent\">" + Web.escapeHtml(rb.getString("sit_log")) + "</a>"); out.println("</div>"); } // out.println(" </tr>"); out.println(" </div>"); out.println("<div class=\"divColor\" id=\"tabBottom\"></div></div>"); if (addLogout) { } else { out.println(" </div>"); } } protected void includeTool(HttpServletRequest req, HttpServletResponse res, ToolConfiguration placement) throws IOException { PrintWriter out = res.getWriter(); // find the tool registered for this ActiveTool tool = ActiveToolManager.getActiveTool(placement.getToolId()); if (tool == null) { // doError(req, res, session); return; } // let the tool do some the work (include) (see note above) String toolUrl = ServerConfigurationService.getToolUrl() + "/" + Web.escapeUrl(placement.getId()); // Reset the tool state if requested if (portalService.isResetRequested(req)) { Session s = SessionManager.getCurrentSession(); ToolSession ts = s.getToolSession(placement.getId()); ts.clearAttributes(); } // this is based on what varuna is currently putting out out.println("<div class=\"portlet\">"); out.println("<div class=\"portletTitleWrap\">"); // emit title information // for the reset button boolean showResetButton = !"false".equals(placement.getConfig().getProperty( TOOLCONFIG_SHOW_RESET_BUTTON)); // 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( TOOLCONFIG_SHOW_HELP_BUTTON)); boolean showHelpButton = helpEnabledGlobally && helpEnabledInTool; String helpActionUrl = ""; if (showHelpButton) { String helpDocId = placement.getConfig().getProperty( TOOLCONFIG_HELP_DOCUMENT_ID); String helpDocUrl = placement.getConfig().getProperty( TOOLCONFIG_HELP_DOCUMENT_URL); if (helpDocUrl != null && helpDocUrl.length() > 0) { helpActionUrl = helpDocUrl; } else { if (helpDocId == null || helpDocId.length() == 0) { helpDocId = tool.getId(); } helpActionUrl = ServerConfigurationService.getHelpUrl(helpDocId); } } out.write("<div class=\"portletTitle\">\n"); out.write("\t<div class=\"title\">\n"); // Charon is not use, if the target needs portal, then this will generate an NPE RenderResult result = ToolRenderService.render(null,placement, req, res, getServletContext()); // This is a new-style reset where the button is in the background // document if (showResetButton) { // Note: This is somewhat brittle code as it assumes that the url // will // always be /tool/ - as an example - one thing that might fail // would // be if the /portal/ string were /tool/ so the right tool url would // be // http://localhost:8080/tool/tool/ - then this code would break // Send the reset url through a redirect step so that any future // refresh of the tool's iframe do not cause a reset String resetUrl = PortalStringUtil.replaceFirst(toolUrl, "/tool/", "/tool-reset/"); out.write("\t\t<a href=\"" + resetUrl + "?panel=Main\" " + " target=\"" + Web.escapeJavascript("Main" + placement.getId()) + "\"" + " title=\"" + Web.escapeHtml(rb.getString("sit_reset")) + "\"><img src=\"/library/image/transparent.gif\" alt=\"" + Web.escapeHtml(rb.getString("sit_reset")) + "\" border=\"1\" /></a>"); } out.write("<h2>" + result.getTitle() + "\n" + "\t</h2></div>\n"); out.write("\t<div class=\"action\">\n"); if (showHelpButton) { out.write(makeHelpButton(helpActionUrl)); } out.write("\t</div><!--gsilver end of the action-->\n"); out.write("</div><!--gsilver end of the portletTitle-->\n"); out.write("</div><!--gsilver end of the portletTitleWrap-->\n"); // Output the iframe for the tool content out.println("<div class=\"portletMainWrap\">"); out.println(result.getContent()); out .println("</div><!--gsilver end of the portletMainWrap--></div><!--gsilver end of the portlet-->"); } protected void includeWorksite(HttpServletRequest req, HttpServletResponse res, Session session, Site site, SitePage page, String toolContextPath, String portalPrefix) throws IOException { // add the page navigation with presence includePageNav(req, res, session, site, page, toolContextPath, portalPrefix); // add the page includePage(req, res, page, toolContextPath, "content"); } /** * Initialize the servlet. * * @param config * The servlet config. * @throws ServletException */ public void init(ServletConfig config) throws ServletException { super.init(config); portalService = org.sakaiproject.portal.api.cover.PortalService.getInstance(); M_log.info("init()"); basicAuth = new BasicAuth(); basicAuth.init(); enableDirect = "true".equals(ServerConfigurationService.getString( "charon.directurl", "true")); } /** * 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 out * The print writer * @param html * If true, output in HTML, else in text. */ protected void showSession(PrintWriter out, boolean html) { // get the current user session information Session s = SessionManager.getCurrentSession(); if (s == null) { out.println("no session established"); if (html) out.println("<br />"); } else { out.println("session: " + s.getId() + " user id: " + s.getUserId() + " enterprise id: " + s.getUserEid() + " started: " + DateFormat.getDateInstance().format(new Date(s.getCreationTime())) + " accessed: " + DateFormat.getDateInstance().format( new Date(s.getLastAccessedTime())) + " inactive after: " + s.getMaxInactiveInterval()); if (html) out.println("<br />"); } ToolSession ts = SessionManager.getCurrentToolSession(); if (ts == null) { out.println("no tool session established"); if (html) out.println("<br />"); } else { out.println("tool session: " + ts.getId() + " started: " + DateFormat.getDateInstance().format(new Date(ts.getCreationTime())) + " accessed: " + DateFormat.getDateInstance().format( new Date(ts.getLastAccessedTime()))); if (html) out.println("<br />"); } } protected PrintWriter startResponse(HttpServletResponse res, String title, String skin, boolean top) throws IOException { // headers res.setContentType("text/html; charset=UTF-8"); 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(); // form the head out .println("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" " + "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" + "<html xmlns=\"http://www.w3.org/1999/xhtml\" lang=\"en\" xml:lang=\"en\">" + " <head>" + " <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />"); // pick the one full portal skin if (skin == null) { skin = ServerConfigurationService.getString("skin.default"); } String skinRepo = ServerConfigurationService.getString("skin.repo"); out.println(" <link href=\"" + skinRepo + "/" + skin + "/portal.css\" type=\"text/css\" rel=\"stylesheet\" media=\"all\" />"); out.println(" <meta http-equiv=\"Content-Style-Type\" content=\"text/css\" />" + " <title>" + Web.escapeHtml(title) + "</title>" + " <script type=\"text/javascript\" src=\"" + getScriptPath() + "headscripts.js\"></script>" + " </head>"); // start the body out .println("<body class=\"portalBody\">"); // if top, mark this as the portal window if (top) { out.println("<script type=\"text/javascript\">"); out.println("var sakaiPortalWindow = \"\";"); out.println("</script>"); } return out; } /** * 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. */ protected 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; } /** * Find the site in the list that has this id - return the position. * * @param value * The site id to find. * @param siteList * The list of Site objects. * @return The index position in siteList of the site with site id = value, * or -1 if not found. */ protected int indexOf(String value, List siteList) { for (int i = 0; i < siteList.size(); i++) { Site site = (Site) siteList.get(i); if (value.equals(site.getId())) { return i; } } return -1; } /** * Check for any just expired sessions and redirect * * @return true if we redirected, false if not */ protected 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 { PrintWriter out = startResponse(res, null, null, false); out.println("<script type=\"text/javascript\">"); out.println("portalWindowRefresh('" + url + "');"); out.println("</script>"); endResponse(out); } /** * 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 */ protected 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); } } /** * If this is a user site, return an id based on the user EID, otherwise * just return the site id. * * @param site * The site. * @return The effective site id. */ protected String getSiteEffectiveId(Site site) { if (SiteService.isUserSite(site.getId())) { try { String userId = SiteService.getSiteUserId(site.getId()); String eid = UserDirectoryService.getUserEid(userId); return SiteService.getUserSiteId(eid); } catch (UserNotDefinedException e) { M_log.warn("getSiteEffectiveId: user eid not found for user site: " + site.getId()); } } return site.getId(); } /** * Do the getSiteVisit, but if not found and the id is a user site, try * translating from user EID to ID. * * @param siteId * The Site Id. * @return The Site. * @throws PermissionException * If not allowed. * @throws IdUnusedException * If not found. */ protected Site getSiteVisit(String siteId) throws PermissionException, IdUnusedException { try { return SiteService.getSiteVisit(siteId); } catch (IdUnusedException e) { if (SiteService.isUserSite(siteId)) { try { String userEid = SiteService.getSiteUserId(siteId); String userId = UserDirectoryService.getUserId(userEid); String alternateSiteId = SiteService.getUserSiteId(userId); return SiteService.getSiteVisit(alternateSiteId); } catch (UserNotDefinedException ee) { } } // re-throw if that didn't work throw e; } } /** * Do the getSiteSkin, adjusting for the overall skin/templates for the portal. * * @return The skin */ protected String getSiteSkin(String siteId) { String skin = SiteService.getSiteSkin(siteId); if (skin == null) { skin = ServerConfigurationService.getString("skin.default"); } String templates = ServerConfigurationService.getString("portal.templates", "neoskin"); String prefix = portalService.getSkinPrefix(); if ( "neoskin".equals(templates)) skin = prefix + skin; return skin; } }