/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/portal/trunk/portal-render-impl/impl/src/java/org/sakaiproject/portal/render/fragment/FragmentToolRenderService.java $
* $Id: FragmentToolRenderService.java 105079 2012-02-24 23:08:11Z 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.render.fragment;
import java.io.IOException;
import java.util.Properties;
import javax.servlet.ServletContext;
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.exception.IdUnusedException;
import org.sakaiproject.exception.PermissionException;
import org.sakaiproject.portal.api.Portal;
import org.sakaiproject.portal.api.PortalService;
import org.sakaiproject.portal.api.StoredState;
import org.sakaiproject.portal.render.api.RenderResult;
import org.sakaiproject.portal.render.api.ToolRenderException;
import org.sakaiproject.portal.render.api.ToolRenderService;
import org.sakaiproject.portal.util.ToolURLManagerImpl;
import org.sakaiproject.site.api.Site;
import org.sakaiproject.site.api.ToolConfiguration;
import org.sakaiproject.site.cover.SiteService;
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.util.Web;
/**
* Attempts to render a tool as a fragment rather than an Iframe.
*
* @author ieb
* @since Sakai 2.4
* @version $Rev: 105079 $
*/
public class FragmentToolRenderService implements ToolRenderService
{
private static final String TOOL_FRAGMENT_PRODUCER_ID = "fragment-producer";
private static final Log log = LogFactory.getLog(FragmentToolRenderService.class);
private PortalService portal;
public FragmentToolRenderService()
{
}
/**
* This is called during render to accept the request into this tool. If the
* placement is handled by the FragmentToolRenderService, this should return
* true, then the render will be invoked.
*/
public boolean accept(Portal portal, ToolConfiguration configuration, HttpServletRequest request,
HttpServletResponse response, ServletContext context)
{
return isFragmentTool(configuration);
}
private boolean isFragmentTool(ToolConfiguration configuration)
{
Properties placementProperties = configuration.getConfig();
String fragmentCapable = placementProperties
.getProperty(TOOL_FRAGMENT_PRODUCER_ID);
if (fragmentCapable == null || fragmentCapable.length() == 0)
{
return false;
}
return true;
}
public boolean preprocess(Portal portal, HttpServletRequest request, HttpServletResponse response,
ServletContext context) throws IOException
{
// for fragments there is no preprocessing, as this is all performed in
// the render cycle
return true;
}
public RenderResult render(Portal portal, final ToolConfiguration toolConfiguration,
final HttpServletRequest request, final HttpServletResponse response,
ServletContext context) throws IOException, ToolRenderException
{
if (isFragmentTool(toolConfiguration))
{
return new RenderResult()
{
public String getContent() throws ToolRenderException
{
Session session = SessionManager.getCurrentSession();
// recognize what to do from the path
String option = request.getPathInfo();
// 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("/");
try
{
doTool(toolConfiguration, request, response, session,
toolConfiguration.getId(), request.getContextPath()
+ request.getServletPath()
+ Web.makePath(parts, 1, 3), Web.makePath(parts,
3, parts.length));
}
catch (Exception e)
{
throw new ToolRenderException("Failed to perform render ", e);
}
// include will render to the output stream
return "";
}
public void setContent(String content)
{
return; // Not allowed
}
public String getTitle() throws ToolRenderException
{
return Web.escapeHtml(toolConfiguration.getTitle());
}
public String getJSR168EditUrl()
{
return null;
}
public String getJSR168HelpUrl()
{
return null;
}
public String getHead()
{
return "";
}
};
// do a named dispatch to the active tool with a fragment set
}
return null;
}
protected void doTool(ToolConfiguration toolConfiguration, HttpServletRequest req,
HttpServletResponse res, Session session, String placementId,
String toolContextPath, String toolPathInfo) throws ToolException,
IOException
{
// Reset the tool state if requested
if (portal.isResetRequested(req))
{
Session s = SessionManager.getCurrentSession();
ToolSession ts = s.getToolSession(placementId);
ts.clearAttributes();
}
// find the tool registered for this
ActiveTool tool = ActiveToolManager.getActiveTool(toolConfiguration.getToolId());
if (tool == null)
{
throw new ToolRenderException(
"Failed to render fragment, no Active Tool found for "
+ toolConfiguration.getToolId());
}
// 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(toolConfiguration.getSiteId());
}
catch (IdUnusedException e)
{
throw new ToolRenderException("No site permissions found for site "
+ toolConfiguration.getSiteId());
}
catch (PermissionException e)
{
throw new ToolRenderException("Permission Deined for placement "
+ toolConfiguration.getId() + " in "
+ toolConfiguration.getSiteId());
}
}
forwardTool(tool, req, res, toolConfiguration, toolConfiguration.getSkin(),
toolContextPath, toolPathInfo);
}
/**
* Taken from Charon, should be in a service
*
* @param tool
* @param req
* @param res
* @param p
* @param skin
* @param toolContextPath
* @param toolPathInfo
* @throws ToolException
*/
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 (portal.isEnableDirect())
{
StoredState ss = portal.getStoredState();
if (ss == null || !toolContextPath.equals(ss.getToolContextPath()))
{
req.setAttribute(ToolURL.MANAGER, new ToolURLManagerImpl(res));
tool.include(req, res, p, toolContextPath, toolPathInfo);
}
else
{
log.debug("Restoring Fragment StoredState [" + ss + "]");
HttpServletRequest sreq = ss.getRequest(req);
Placement splacement = ss.getPlacement();
String stoolContext = ss.getToolContextPath();
String stoolPathInfo = ss.getToolPathInfo();
ActiveTool stool = ActiveToolManager.getActiveTool(p.getToolId());
String sskin = ss.getSkin();
req.setAttribute(ToolURL.MANAGER, new ToolURLManagerImpl(res));
stool.include(sreq, res, splacement, stoolContext, stoolPathInfo);
// this is correct as we have already checked the context path
// of the desitination
portal.setStoredState(null);
}
}
else
{
req.setAttribute(ToolURL.MANAGER, new ToolURLManagerImpl(res));
tool.include(req, res, p, toolContextPath, toolPathInfo);
}
}
public void setPortalService(PortalService portal)
{
this.portal = portal;
}
public void reset(ToolConfiguration configuration)
{
}
}