/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/site-manage/trunk/site-association-util/util/src/java/org/sakaiproject/siteassociation/tool/servlet/SiteAssocJsfTool.java $ * $Id: SiteAssocJsfTool.java 84579 2010-11-10 19:06:20Z zqian@umich.edu $ *********************************************************************************** * * Copyright (c) 2006, 2007 The Sakai Foundation. * * Licensed under the Educational Community License, Version 1.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/ecl1.php * * 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.siteassociation.tool.servlet; import java.io.IOException; import java.util.Enumeration; import java.util.Map; import javax.servlet.RequestDispatcher; import javax.servlet.ServletConfig; import javax.servlet.ServletException; 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.ComponentManager; import org.sakaiproject.tool.api.ToolSession; import org.sakaiproject.tool.api.SessionManager; import org.sakaiproject.tool.api.ActiveTool; import org.sakaiproject.tool.api.Tool; import org.sakaiproject.tool.api.ToolException; import org.sakaiproject.tool.api.ActiveToolManager; import org.sakaiproject.tool.api.ToolManager; import org.sakaiproject.jsf.util.JsfTool; import org.sakaiproject.util.Web; public class SiteAssocJsfTool extends JsfTool { /** * */ private static final long serialVersionUID = -976719461956856669L; private static final Log logger = LogFactory.getLog(SiteAssocJsfTool.class); private SessionManager sessionManager; private ActiveToolManager activeToolManager; private ToolManager toolManager; private static final String HELPER_EXT = ".helper"; private static final String PANEL = "panel"; private static final String HELPER_SESSION_PREFIX = "session."; // FIXME: http://bugs.sakaiproject.org/jira/browse/GM-88 private static final String MYFACES_VIEW_COLLECTION = "org.apache.myfaces.application.jsp.JspStateManagerImpl.SERIALIZED_VIEW"; private static final String STORED_MYFACES_VIEW_COLLECTION = "STORED_" + MYFACES_VIEW_COLLECTION; // If this URL is requested, the helper is done and ready to return public static final String HELPER_RETURN_NOTIFICATION = "/returnToSender"; // Override init to inject necessary components via ComponentManager cover @Override public void init(ServletConfig config) throws ServletException { super.init(config); sessionManager = (SessionManager) ComponentManager .get("org.sakaiproject.tool.api.SessionManager"); activeToolManager = (ActiveToolManager) ComponentManager .get("org.sakaiproject.tool.api.ActiveToolManager"); toolManager = (ToolManager) ComponentManager .get("org.sakaiproject.tool.api.ToolManager"); } @Override protected void dispatch(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { logger.debug("dispatch()"); String target = req.getPathInfo(); ToolSession session = sessionManager.getCurrentToolSession(); if (logger.isDebugEnabled()) { Map<String, String[]> reqParms = req.getParameterMap(); for(Map.Entry<String, String[]> entry : reqParms.entrySet()) { String reqParmKey = entry.getKey(); StringBuffer sb = new StringBuffer(); sb.append("REQ_PARM: "); sb.append(reqParmKey); sb.append(" = "); sb.append('['); String[] reqParm = reqParms.get(reqParmKey); for (int i = 0; i < reqParm.length;) { sb.append(reqParm[i]); if (++i < reqParm.length) { sb.append(", "); } } sb.append(']'); logger.debug(sb.toString()); } Enumeration<String> sessionParmNames = session.getAttributeNames(); while (sessionParmNames.hasMoreElements()) { String sessionParmName = sessionParmNames.nextElement(); logger.debug("SESS_PARM: " + sessionParmName + " = " + session.getAttribute(sessionParmName)); } } // see if this is the helper trying to return to caller if (HELPER_RETURN_NOTIFICATION.equals(target)) { target = (String) session.getAttribute(toolManager.getCurrentTool() .getId() + Tool.HELPER_DONE_URL); if (target != null) { // FIXME: Workaround for // http://bugs.sakaiproject.org/jira/browse/GM-88 Object viewCollection = session .getAttribute(STORED_MYFACES_VIEW_COLLECTION); if (viewCollection != null) { session.removeAttribute(STORED_MYFACES_VIEW_COLLECTION); session.setAttribute(MYFACES_VIEW_COLLECTION, viewCollection); } session.removeAttribute(toolManager.getCurrentTool().getId() + Tool.HELPER_DONE_URL); res.sendRedirect(target); return; } } // Need this here until ToolServlet is updated to support this in // sendToHelper method // http://bugs.sakaiproject.org/jira/browse/SAK-9043 // http://bugs.sakaiproject.org/jira/browse/GM-69 Enumeration<String> params = req.getParameterNames(); while (params.hasMoreElements()) { String paramName = params.nextElement(); if (paramName.startsWith(HELPER_SESSION_PREFIX)) { String attributeName = paramName .substring(HELPER_SESSION_PREFIX.length()); session .setAttribute(attributeName, req .getParameter(paramName)); } } if (sendToHelper(req, res, target)) { return; } // see if we have a resource request - i.e. a path with an extension, // and one that is not the JSF_EXT if (isResourceRequest(target)) { // get a dispatcher to the path RequestDispatcher resourceDispatcher = getServletContext() .getRequestDispatcher(target); if (resourceDispatcher != null) { resourceDispatcher.forward(req, res); return; } } if ("Title".equals(req.getParameter(PANEL))) { // This allows only one Title JSF for each tool target = "/title.jsf"; } else { if ((target == null) || "/".equals(target)) { target = computeDefaultTarget(); // make sure it's a valid path if (!target.startsWith("/")) { target = "/" + target; } // now that we've messed with the URL, send a redirect to make // it official res.sendRedirect(Web.returnUrl(req, target)); return; } // see if we want to change the specifically requested view String newTarget = redirectRequestedTarget(target); // make sure it's a valid path if (!newTarget.startsWith("/")) { newTarget = "/" + newTarget; } if (!newTarget.equals(target)) { // now that we've messed with the URL, send a redirect to make // it official res.sendRedirect(Web.returnUrl(req, newTarget)); return; } target = newTarget; // store this if (m_defaultToLastView) { session.setAttribute(LAST_VIEW_VISITED, target); } } // add the configured folder root and extension (if missing) target = m_path + target; // add the default JSF extension (if we have no extension) int lastSlash = target.lastIndexOf('/'); int lastDot = target.lastIndexOf('.'); if ((lastDot < 0) || (lastDot < lastSlash)) { target += JSF_EXT; } // set the information that can be removed from return URLs req.setAttribute(URL_PATH, m_path); req.setAttribute(URL_EXT, ".jsp"); // set the sakai request object wrappers to provide the native, not // Sakai set up, URL information // - this assures that the FacesServlet can dispatch to the proper view // based on the path info req.setAttribute(Tool.NATIVE_URL, Tool.NATIVE_URL); // TODO: Should setting the HTTP headers be moved up to the portal level // as well? 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"); // dispatch to the target /* * M_log.debug("dispatching path: " + req.getPathInfo() + " to: " + * target + " context: " + getServletContext().getServletContextName()); */ RequestDispatcher dispatcher = getServletContext() .getRequestDispatcher(target); dispatcher.forward(req, res); // restore the request object req.removeAttribute(Tool.NATIVE_URL); req.removeAttribute(URL_PATH); req.removeAttribute(URL_EXT); } protected boolean sendToHelper(HttpServletRequest req, HttpServletResponse res, String target) throws ToolException { if (target == null) { target = "/"; } // 0 parts means the target was just "/", otherwise parts[0] = "", // parts[1] = item id, parts[2] if present is "edit"... String[] parts = target.split("/"); if (parts.length < 2) { return false; } if (!parts[1].endsWith(HELPER_EXT)) { return false; } // calc helper id int posEnd = parts[1].lastIndexOf('.'); String helperId = target.substring(1, posEnd + 1); ActiveTool helperTool = activeToolManager.getActiveTool(helperId); ToolSession toolSession = sessionManager.getCurrentToolSession(); if (toolSession.getAttribute(helperTool.getId() + Tool.HELPER_DONE_URL) == null) { toolSession.setAttribute(helperTool.getId() + Tool.HELPER_DONE_URL, req.getContextPath() + req.getServletPath() + computeDefaultTarget()); } String context = req.getContextPath() + req.getServletPath() + Web.makePath(parts, 1, 2); String toolPath = Web.makePath(parts, 2, parts.length); // FIXME: Workaround for http://bugs.sakaiproject.org/jira/browse/GM-88 // Don't overwrite if already stored if (toolSession.getAttribute(STORED_MYFACES_VIEW_COLLECTION) == null) { Object viewCollection = toolSession .getAttribute(MYFACES_VIEW_COLLECTION); if (viewCollection != null) { toolSession.removeAttribute(MYFACES_VIEW_COLLECTION); toolSession.setAttribute(STORED_MYFACES_VIEW_COLLECTION, viewCollection); } } helperTool.help(req, res, context, toolPath); return true; // was handled as helper call } }