/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/msgcntr/trunk/messageforums-app/src/java/org/sakaiproject/tool/messageforums/MessageForumsFilePickerServlet.java $ * $Id: MessageForumsFilePickerServlet.java 9227 2006-05-15 15:02:42Z cwen@iupui.edu $ *********************************************************************************** * * Copyright (c) 2003, 2004, 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.tool.messageforums; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.Enumeration; import javax.servlet.RequestDispatcher; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.sakaiproject.site.api.SiteService; import org.sakaiproject.tool.api.ToolSession; import org.sakaiproject.tool.cover.SessionManager; import org.sakaiproject.tool.api.ActiveTool; import org.sakaiproject.tool.api.Tool; import org.sakaiproject.tool.cover.ActiveToolManager; import org.sakaiproject.api.app.messageforums.ui.DiscussionForumManager; import org.sakaiproject.component.cover.ComponentManager; import org.sakaiproject.entitybroker.EntityReference; import org.sakaiproject.entitybroker.access.HttpServletAccessProvider; import org.sakaiproject.entitybroker.access.HttpServletAccessProviderManager; import org.sakaiproject.exception.IdUnusedException; import org.sakaiproject.jsf.util.JsfTool; import org.sakaiproject.util.Web; import org.sakaiproject.tool.api.ToolException; /** * @author Chen Wen * @version $Id$ * */ public class MessageForumsFilePickerServlet extends JsfTool implements HttpServletAccessProvider { private static final String HELPER_EXT = ".helper"; private static final String HELPER_SESSION_PREFIX = "session."; private boolean initComplete = false; private SiteService siteService; private HttpServletAccessProviderManager accessProviderManager; private DiscussionForumManager forumManager; protected void dispatch(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { // NOTE: this is a simple path dispatching, taking the path as the view // id = jsp file name for the view, // with default used if no path and a path prefix as configured. // TODO: need to allow other sorts of dispatching, such as pulling out // drill-down ids and making them // available to the JSF // build up the target that will be dispatched to String target = req.getPathInfo(); // see if we have a helper request 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 { ToolSession session = SessionManager.getCurrentToolSession(); if (target == null || "/".equals(target)) { target = computeDefaultTarget(true); // 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 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 { String path = req.getPathInfo(); if (path == null) path = "/"; // if synoptic helper is obscuring add attachment helper, remove it final int helperIndex = path.indexOf("sakai.filepicker"); // filepicker helper should be first part of path if (helperIndex > 1 ) { path = path.substring(helperIndex-1); target = path; } // // 0 parts means the path was just "/", otherwise parts[0] = "", // parts[1] = item id, parts[2] if present is "edit"... String[] parts = path.split("/"); if (parts.length < 2) { return false; } /* if (parts.length < 3) { // return false; }*/ if (!parts[1].endsWith(HELPER_EXT)) { return false; } /* if (!parts[2].endsWith(HELPER_EXT)) { return false; } */ ToolSession toolSession = SessionManager.getCurrentToolSession(); Enumeration params = req.getParameterNames(); while (params.hasMoreElements()) { String paramName = (String) params.nextElement(); if (paramName.startsWith(HELPER_SESSION_PREFIX)) { String attributeName = paramName.substring(HELPER_SESSION_PREFIX.length()); toolSession.setAttribute(attributeName, req.getParameter(paramName)); } } // calc helper id int posEnd = parts[1].lastIndexOf("."); ////int posEnd = parts[2].lastIndexOf("."); String helperId = target.substring(1, posEnd + 1); ////String helperId = parts[2].substring(0, posEnd); ActiveTool helperTool = ActiveToolManager.getActiveTool(helperId); if (toolSession.getAttribute(helperTool.getId() + Tool.HELPER_DONE_URL) == null && !target.equals("/sakai.filepicker.helper")) { toolSession.setAttribute(helperTool.getId() + Tool.HELPER_DONE_URL, req.getContextPath() + req.getServletPath() + computeDefaultTarget(true)); } String context = req.getContextPath() + req.getServletPath() + Web.makePath(parts, 1, 2); ////String context = req.getContextPath() + req.getServletPath() + Web.makePath(parts, 2, 3); String toolPath = Web.makePath(parts, 2, parts.length); ////String toolPath = Web.makePath(parts, 3, parts.length); helperTool.help(req, res, context, toolPath); return true; // was handled as helper call } protected String computeDefaultTarget(boolean lastVisited) { // setup for the default view as configured String target = "/" + m_default; // if we are doing lastVisit and there's a last-visited view, for this // tool placement / user, use that if (lastVisited) { ToolSession session = SessionManager.getCurrentToolSession(); String last = (String) session.getAttribute(LAST_VIEW_VISITED); if (last != null) { target = last; } } return target; } /** * Initialize the servlet. * * @param config * The servlet config. * @throws ServletException */ public void init(ServletConfig config) throws ServletException { super.init(config); try { //load service level dependecies from the ComponentManager siteService = (SiteService) ComponentManager.get("org.sakaiproject.site.api.SiteService"); accessProviderManager = (HttpServletAccessProviderManager) ComponentManager .get("org.sakaiproject.entitybroker.access.HttpServletAccessProviderManager"); forumManager = (DiscussionForumManager) ComponentManager .get("org.sakaiproject.api.app.messageforums.ui.DiscussionForumManager"); //register forum Entity prefixes for direct servlet request handling if (accessProviderManager != null) { accessProviderManager.registerProvider("forum_topic", this); accessProviderManager.registerProvider("forum", this); accessProviderManager.registerProvider("forum_message", this); } //mark initialization of dependecies as complete if (siteService != null && forumManager != null) initComplete = true; } catch (Exception e) { e.printStackTrace(); } } public void handleAccess(HttpServletRequest req, HttpServletResponse res, EntityReference ref) { //don't bother if the user is not logged in if (req.getRemoteUser() == null) { try { String url = req.getRequestURL().toString(); String context = req.getContextPath(); String prefix = url.substring(0,url.lastIndexOf(context)); res.sendRedirect(prefix + "/authn/login?url=" + URLEncoder.encode(req.getRequestURL().toString(), "UTF-8")); return; } catch (UnsupportedEncodingException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } String[] parts = req.getPathInfo().split("/"); //ensure we have our dependencies and something reassembling proper input if (initComplete && parts.length > 2) { String context = ""; if ("forum_topic".equals(parts[1])) context = forumManager.getContextForTopicById(Long.valueOf(parts[2])); else if ("forum".equals(parts[1])) context = forumManager.getContextForForumById(Long.valueOf(parts[2])); else if ("forum_message".equals(parts[1])) context = forumManager.getContextForMessageById(Long.valueOf(parts[2])); String placementId = ""; String target = ""; //Calculate the placement for the Entity... if you know of a better way, please //replace this! try { if (siteService.getSite(context).getToolForCommonId("sakai.forums") != null) { placementId = siteService.getSite(context) .getToolForCommonId("sakai.forums").getId(); } else { placementId = siteService.getSite(context) .getToolForCommonId("sakai.messagecenter").getId(); } } catch (IdUnusedException iue) { iue.printStackTrace(); } //TODO: I've tried (and failed) a number of things here to try to get this to work //without a redirect using a block of setting all the placement and session things //into the the threadlocal manager here resulted in the closest thing... rendered //the page, but links were broken, might be doable with more time or fresh eyes //though. //direct the request to the proper 'direct' view with needed parameters if ("forum_topic".equals(parts[1])) { req.setAttribute("topicId", parts[2]); target = "/jsp/discussionForum/message/dfAllMessagesDirect.jsf?topicId=" + parts[2] + "&placementId=" + placementId; } else if ("forum".equals(parts[1])) { target = "/jsp/discussionForum/forum/dfForumDirect.jsf?forumId=" + parts[2] + "&placementId=" + placementId; } else if ("forum_message".equals(parts[1])) { target = "/jsp/discussionForum/message/dfViewMessageDirect.jsf?messageId=" + parts[2] + "&placementId=" + placementId + "&topicId=" + forumManager.getMessageById(Long.valueOf(parts[2])).getTopic().getId() + "&forumId=" + forumManager.ForumIdForMessage(Long.valueOf(parts[2])); } // dispatch to the target RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(target); try { dispatcher.forward(req, res); } catch (ServletException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } } }