/********************************************************************************** * $URL:https://source.sakaiproject.org/svn/osp/trunk/presentation/tool/src/java/org/theospi/portfolio/presentation/control/ViewPresentationControl.java $ * $Id:ViewPresentationControl.java 9134 2006-05-08 20:28:42Z chmaurer@iupui.edu $ *********************************************************************************** * * 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.theospi.portfolio.presentation.control; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.URIResolver; import javax.xml.transform.stream.StreamSource; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jdom.Document; import org.sakaiproject.component.cover.ServerConfigurationService; import org.sakaiproject.exception.IdUnusedException; import org.sakaiproject.metaobj.shared.ArtifactFinder; import org.sakaiproject.metaobj.shared.ArtifactFinderManager; import org.sakaiproject.metaobj.shared.mgt.HomeFactory; import org.sakaiproject.metaobj.shared.model.Agent; import org.sakaiproject.metaobj.shared.model.Id; import org.sakaiproject.metaobj.shared.model.PersistenceException; import org.sakaiproject.metaobj.utils.mvc.intf.LoadObjectController; import org.sakaiproject.site.api.Site; import org.sakaiproject.site.api.ToolConfiguration; import org.sakaiproject.site.cover.SiteService; import org.sakaiproject.tool.api.ToolSession; import org.sakaiproject.tool.cover.SessionManager; import org.sakaiproject.tool.cover.ToolManager; import org.sakaiproject.tool.api.Tool; import org.springframework.validation.BindException; import org.springframework.validation.Errors; import org.springframework.web.servlet.ModelAndView; import org.theospi.portfolio.presentation.PresentationFunctionConstants; import org.theospi.portfolio.presentation.PresentationManager; import org.theospi.portfolio.presentation.model.Presentation; import org.theospi.portfolio.presentation.model.PresentationComment; import org.theospi.portfolio.presentation.model.PresentationLog; import org.theospi.portfolio.security.AuthorizationFacade; import org.theospi.portfolio.shared.model.Node; import org.theospi.portfolio.shared.model.OspException; import java.io.ObjectOutputStream; import java.io.ObjectInputStream; import java.io.FileOutputStream; import java.io.FileInputStream; import java.io.File; import net.sf.ehcache.Cache; import net.sf.ehcache.CacheManager; import net.sf.ehcache.Element; /** * Created by IntelliJ IDEA. * User: John Ellis * Date: May 25, 2004 * Time: 1:52:39 PM * To change this template use File | Settings | File Templates. */ public class ViewPresentationControl extends AbstractPresentationController implements LoadObjectController { protected static final Log logger = LogFactory.getLog(ViewPresentationControl.class); private HomeFactory homeFactory = null; private ArtifactFinder artifactFinder = null; private AuthorizationFacade authzManager = null; private ArtifactFinderManager artifactFinderManager; private Hashtable presentationTemplateCache = new Hashtable(); private URIResolver uriResolver; private TransformerFactory transformerFactory; private static Cache cache = setupCache(); public static final String XSL_SITE_ID = "sakaiSiteId"; public static final String XSL_PRESENTATION_TYPE = "sakaiPresentationType"; public static final String XSL_PRESENTATION_ID = "sakaiPresentationId"; private static Cache setupCache() { // detailed configuration is in presentation/tool/src/bundle/ehcache.xml, // which ends up in tomcat/webapps/osp-presentation-tool/WEB-INF/classes/ if ( !ServerConfigurationService.getBoolean("cache.osp.presentation.data",false) ) return null; String cacheName = "org.theospi.portfolio.presentation.control.ViewPresentationControl.XML"; CacheManager cacheManager = CacheManager.create(); if (cacheManager == null) return null; try { cacheManager.addCache(cacheName); return cacheManager.getCache(cacheName); } catch (Exception e) { logger.warn("ViewPresentationControl.setupCache failed"); } return null; } public Object fillBackingObject(Object incomingModel, Map request, Map session, Map application) throws Exception { PresentationManager presentationManager = getPresentationManager(); Presentation presentation = (Presentation) incomingModel; if (presentation.getSecretExportKey() != null) { String secretExportKey = presentation.getSecretExportKey(); presentation = presentationManager.getPresentation(presentation.getId(), secretExportKey); presentation.setSecretExportKey(secretExportKey); logger.debug("User " + getAuthManager().getAgent().getId() + " is viewing a presentation with a secret export key: " + presentation.getId().getValue()); return presentation; } else { // if it exists, get the presentation from memory that is being edited Presentation previewPres = (Presentation) session.get("presentation"); if (previewPres != null && previewPres.getId().getValue().equals(presentation.getId().getValue())) { //side step any authz issues as the presentation only exists in the users session previewPres.setIsPublic(true); previewPres.setIsPreview(true); logger.debug("User " + getAuthManager().getAgent().getId() + " is viewing a presentation from session: " + previewPres.getId().getValue()); return previewPres; } if ( presentation.getId() == null ) { logger.warn("Attempt to view invalid/unspecified presentation by user " + getAuthManager().getAgent().getId() ); return null; } else { logger.debug("User " + getAuthManager().getAgent().getId() + " is viewing a presentation by id: " + presentation.getId().getValue()); return getPresentationManager().getLightweightPresentation(presentation.getId()); } } } public ModelAndView handleRequest(Object requestModel, Map request, Map session, Map application, Errors errors) { Presentation pres = (Presentation) requestModel; // check for unspecified or invalid portfolio if ( pres == null ) return new ModelAndView("expired"); if (pres.getSecretExportKey() == null) { if (!pres.getIsPublic()) { if (getAuthManager().getAgent().isInRole(Agent.ROLE_ANONYMOUS)){ try { Site site = SiteService.getSite(pres.getSiteId()); ToolConfiguration toolConfig = site.getToolForCommonId(PresentationFunctionConstants.PRES_TOOL_ID); String placement = toolConfig.getId(); ToolSession ts = SessionManager.getCurrentSession().getToolSession(placement); SessionManager.setCurrentToolSession(ts); SessionManager.getCurrentSession().setAttribute(Tool.HELPER_DONE_URL, pres.getExternalUri()); Map model = new Hashtable(); model.put("sakai.tool.placement.id", placement); return new ModelAndView("authnRedirect", model); } catch (IdUnusedException e) { logger.error("", e); } } else { boolean viewAll = ServerConfigurationService.getBoolean("osp.presentation.viewall", false); boolean canReview = getAuthzManager().isAuthorized(PresentationFunctionConstants.REVIEW_PRESENTATION, getIdManager().getId(pres.getSiteId() ) ); boolean canView = getAuthzManager().isAuthorized(PresentationFunctionConstants.VIEW_PRESENTATION, pres.getId()); if ( !canView && (!viewAll || !canReview) ) return new ModelAndView("expired"); // display expired or invalid message } } if (pres.isExpired() && !pres.getOwner().getId().equals(getAuthManager().getAgent().getId())) { return new ModelAndView("expired"); // display expired or invalid message } } if (!pres.isPreview()) { logViewedPresentation(pres); } Hashtable model = new Hashtable(); try { model.put("presentation", pres); Document doc = null; if (pres.getPresentationType().equals(Presentation.TEMPLATE_TYPE)) { // have to check modified dates rather than depending upon // clearing the cache when something changes. In a cluster // the event that invalidates the cache may occur on a different // system. For previews always force current data. Otherwise // invalidate cache if presentation or template on which it is // based changes. if (cache != null && !pres.isPreview()) { Element element = cache.get(pres.getId()); if (element != null && pres.getModified().getTime() <= element.getCreationTime() && pres.getTemplate().getModified().getTime() <= element.getCreationTime()) { doc = (Document)element.getValue(); } } if (doc == null) { doc = getPresentationManager().createDocument(pres); if (cache != null && doc != null) cache.put(new Element(pres.getId(), doc)); } } else { String page = (String)request.get("page"); if (pres.isPreview()) { doc = getPresentationManager().getPresentationPreviewLayoutAsXml(pres, page); } else { doc = getPresentationManager().getPresentationLayoutAsXml(pres, page); } if(doc == null){ model.put("noPagesFound", true); return new ModelAndView("notFound", model); } } Site site = SiteService.getSite(pres.getSiteId()); getAuthzManager().pushAuthzGroups(site.getId()); ToolConfiguration toolConfig = site.getToolForCommonId(PresentationFunctionConstants.PRES_TOOL_ID); String placement = toolConfig.getId(); model.put("placementId", placement); if(doc != null) model.put("document", doc); else return new ModelAndView("notFound", model); model.put("renderer", getTransformer(pres, request)); model.put("uriResolver", getUriResolver()); if (!getAuthManager().getAgent().isInRole(Agent.ROLE_ANONYMOUS)) { model.put("currentAgent", getAuthManager().getAgent()); } if (!pres.isPreview()) { model.put("comments", getPresentationManager().getPresentationComments(pres.getId(), getAuthManager().getAgent())); boolean allowComments = getAuthzManager().isAuthorized( PresentationFunctionConstants.COMMENT_PRESENTATION, pres.getId() ); model.put("allowComments", allowComments ); } else { model.put("allowComments", pres.isAllowComments()); } if (request.get(BindException.MODEL_KEY_PREFIX + "newComment") == null) { request.put(BindException.MODEL_KEY_PREFIX + "newComment", new BindException(new PresentationComment(), "newComment")); } } catch (PersistenceException e) { logger.error("",e); throw new OspException(e); } catch (IdUnusedException e) { logger.error("", e); } boolean headers = pres.getTemplate().isIncludeHeaderAndFooter(); String viewName = "withoutHeader"; if (headers) { if (ToolManager.getCurrentPlacement() == null) { viewName = "withHeaderStandalone"; } else { viewName = "withHeader"; } } return new ModelAndView(viewName, model); } /** * creates a new log that this presentation has been viewed * @param pres */ protected void logViewedPresentation(Presentation pres){ PresentationLog log = new PresentationLog(); log.setPresentation(pres); log.setViewDate(new java.util.Date()); log.setViewer(getAuthManager().getAgent()); getPresentationManager().storePresentationLog(log); } // cache the template... protected Transformer getTransformer(Presentation presentation, Map request) throws PersistenceException { Id renderer = presentation.getTemplate().getRenderer(); TransformerWrapper wrapper = (TransformerWrapper) presentationTemplateCache.get(renderer); if (wrapper == null) { wrapper = new TransformerWrapper(); wrapper.modified = 0; } Node xsl = getPresentationManager().getNode(renderer); if (xsl.getTechnicalMetadata().getLastModified().getTime() > wrapper.modified) { try { TransformerFactory tf = getTransformerFactory(); tf.setURIResolver(getUriResolver()); wrapper.transformer = tf.newTransformer(new StreamSource(xsl.getInputStream())); wrapper.modified = xsl.getTechnicalMetadata().getLastModified() .getTime(); } catch (TransformerConfigurationException e) { throw new OspException(e); } } wrapper.transformer.clearParameters(); //send request params in as transform params for(Iterator i=request.entrySet().iterator();i.hasNext();){ Entry entry = (Entry) i.next(); wrapper.transformer.setParameter(entry.getKey().toString(),entry.getValue().toString()); } wrapper.transformer.setParameter(XSL_SITE_ID, presentation.getSiteId()); if (presentation.getIsFreeFormType()) { wrapper.transformer.setParameter(XSL_PRESENTATION_TYPE, presentation.getPresentationType()); } else if (presentation.getTemplate() != null) { wrapper.transformer.setParameter(XSL_PRESENTATION_TYPE, presentation.getTemplate().getId().getValue()); } wrapper.transformer.setParameter(XSL_PRESENTATION_ID, presentation.getId().getValue()); presentationTemplateCache.put(renderer,wrapper); return wrapper.transformer; } private class TransformerWrapper { public long modified; public Transformer transformer; } public HomeFactory getHomeFactory() { return homeFactory; } public void setHomeFactory(HomeFactory homeFactory) { this.homeFactory = homeFactory; } public ArtifactFinder getArtifactFinder() { return artifactFinder; } public void setArtifactFinder(ArtifactFinder artifactFinder) { this.artifactFinder = artifactFinder; } public AuthorizationFacade getAuthzManager() { return authzManager; } public void setAuthzManager(AuthorizationFacade authzManager) { this.authzManager = authzManager; } public ArtifactFinderManager getArtifactFinderManager() { return artifactFinderManager; } public void setArtifactFinderManager(ArtifactFinderManager artifactFinderManager) { this.artifactFinderManager = artifactFinderManager; } public Hashtable getPresentationTemplateCache() { return presentationTemplateCache; } public void setPresentationTemplateCache(Hashtable presentationTemplateCache) { this.presentationTemplateCache = presentationTemplateCache; } public TransformerFactory getTransformerFactory() { if (transformerFactory == null) { transformerFactory = TransformerFactory.newInstance(); } return transformerFactory; } public void setTransformerFactory(TransformerFactory transformerFactory) { this.transformerFactory = transformerFactory; } public URIResolver getUriResolver() { return uriResolver; } public void setUriResolver(URIResolver uriResolver) { this.uriResolver = uriResolver; getTransformerFactory().setURIResolver(uriResolver); } }