/**********************************************************************************
* $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
}
}