/********************************************************************************** * $URL: https://source.sakaiproject.org/svn/portal/trunk/portal-xsl/tool/src/java/org/sakaiproject/portal/xsltcharon/impl/XsltRenderEngine.java $ * $Id: XsltRenderEngine.java 112035 2012-08-31 16:51:48Z earle.nietzel@gmail.com $ *********************************************************************************** * * Copyright (c) 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.xsltcharon.impl; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.component.cover.ComponentManager; import org.sakaiproject.component.cover.ServerConfigurationService; import org.sakaiproject.portal.api.Portal; import org.sakaiproject.portal.api.PortalRenderContext; import org.sakaiproject.portal.api.PortalRenderEngine; import org.sakaiproject.portal.api.PortalService; import org.sakaiproject.tool.api.Placement; import org.sakaiproject.webapp.api.WebappResourceManager; import org.w3c.dom.Document; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.transform.*; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import java.io.IOException; import java.io.InputStream; import java.io.Writer; import java.net.MalformedURLException; import java.net.URL; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; /** * Created by IntelliJ IDEA. * User: johnellis * Date: Jul 13, 2007 * Time: 12:06:22 PM * To change this template use File | Settings | File Templates. */ public class XsltRenderEngine implements PortalRenderEngine { private static final String XSLT_CONTEXT = "xsltCharon"; private static final Log log = LogFactory.getLog(XsltRenderEngine.class); /** injected **/ private PortalService portalService; private String defaultTransformerPath; private Templates defaultTemplates; private URIResolver libraryServletResolver; private URIResolver servletResolver; private Map<String, Templates> templates = new Hashtable<String, Templates>(); private Map<String, String> transformerPaths; private WebappResourceManager libraryWebappResourceManager; private WebappResourceManager portalWebappResourceManager; private boolean cacheTemplates = true; private static final String XSLT_PORTAL_CACHE_TEMPLATES = "xslt-portal.cacheTemplates"; public XsltRenderEngine() { } public XsltRenderEngine(PortalService portalService) { this.portalService = portalService; } /** * Initialise the render engine * * @throws Exception */ public void init() throws Exception { } public void springInit() { if (ServerConfigurationService.getString(XSLT_PORTAL_CACHE_TEMPLATES) != null){ try { cacheTemplates = Boolean.parseBoolean(ServerConfigurationService.getString(XSLT_PORTAL_CACHE_TEMPLATES, "true")); } catch (Exception e) { log.error("can't parse " + XSLT_PORTAL_CACHE_TEMPLATES + " into a boolean", e); } } getPortalService().addRenderEngine(XSLT_CONTEXT, this); try { setDefaultTemplates(createTemplate()); setupTemplates(); } catch (MalformedURLException e) { log.error("unable to init portal transformation", e); } catch (TransformerConfigurationException e) { log.error("unable to init portal transformation", e); } catch (IOException e) { log.error("unable to init portal transformation", e); } setServletResolver(new ServletResourceUriResolver(getPortalWebappResourceManager())); //setLibraryServletResolver(new ServletResourceUriResolver(getLibraryWebappResourceManager())); } protected void setupTemplates() throws IOException, TransformerConfigurationException { for (Iterator<Map.Entry<String, String>> i=getTransformerPaths().entrySet().iterator(); i.hasNext();) { Map.Entry<String, String> entry = i.next(); getTemplates().put(entry.getKey(), createTemplate(entry.getValue())); } } public void destroy() { getPortalService().removeRenderEngine(XSLT_CONTEXT, this); } /** * generate a non thread safe render context for the current * request/thread/operation * * @param request * @return new render context */ public PortalRenderContext newRenderContext(HttpServletRequest request) { PortalRenderContext base = getPortalService().getRenderEngine(Portal.DEFAULT_PORTAL_CONTEXT, request).newRenderContext(request); return new XsltRenderContext(this, base, request); } /** * Render a PortalRenderContext against a template. The real template may be * based on a skining name, out output will be send to the Writer * * @param template * @param rcontext * @param out * @throws Exception */ public void render(String template, PortalRenderContext rcontext, Writer out) throws Exception { XsltRenderContext xrc = (XsltRenderContext) rcontext; if (log.isTraceEnabled()) { log.trace("Portal trace is on, dumping PortalRenderContext to log:\n" + xrc.dump()); } if (template.equals("site")) { Document doc = xrc.produceDocument(); writeDocument(doc, out, xrc); } else { xrc.getBaseContext().getRenderEngine().render(template, xrc.getBaseContext(), out); } } protected void writeDocument(Document doc, Writer out, XsltRenderContext xrc) { try { StreamResult outputTarget = new StreamResult(out); Transformer transformer = getTransformer(xrc); transformer.transform(new DOMSource(doc), outputTarget); } catch (TransformerException e) { throw new RuntimeException(e); } } public Transformer getTransformer(XsltRenderContext xrc) { try { Templates templates = null; boolean skin = false; if (xrc.getAlternateTemplate() != null) { templates = getTemplates().get(xrc.getAlternateTemplate()); } // test seperately in case the param wasnt' correct if (templates == null) { templates = getSkinTemplates(xrc); skin = true; } if (templates == null) { templates = getDefaultTemplates(); skin = false; } Transformer trans = templates.newTransformer(); trans.setURIResolver(getServletResolver(skin)); return trans; } catch (TransformerConfigurationException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } } protected Templates getSkinTemplates(XsltRenderContext xrc) throws IOException, TransformerConfigurationException { String skin = (String) xrc.get("pageSkin"); Templates returned = null; if (cacheTemplates) { returned = getTemplates().get("skin." + skin); if (returned != null) { return returned; } } InputStream skinStream = getLibraryWebappResourceManager().getResourceAsStream( "/skin/" + skin + "/portal.xslt"); if (skinStream == null) { // check the default one String defaultSkin = ServerConfigurationService.getString("skin.default"); skinStream = getLibraryWebappResourceManager().getResourceAsStream( "/skin/" + defaultSkin + "/portal.xslt"); if (skinStream == null) { return null; } } returned = createTemplate(skinStream); if (cacheTemplates) { getTemplates().put("skin." + skin, returned); } return returned; } protected URIResolver getServletResolver(boolean skin) { if (skin) { return getLibraryServletResolver(); } else { return getServletResolver(); } } public Templates getDefaultTemplates() { return defaultTemplates; } public void setDefaultTemplates(Templates defaultTemplates) { this.defaultTemplates = defaultTemplates; } public URIResolver getServletResolver() { return servletResolver; } public void setServletResolver(URIResolver servletResolver) { this.servletResolver = servletResolver; } /** * prepare for a forward operation in the render engine, this might include * modifying the request attributes. * * @param req * @param res * @param p * @param skin */ public void setupForward(HttpServletRequest req, HttpServletResponse res, Placement p, String skin) { getPortalService().getRenderEngine(Portal.DEFAULT_PORTAL_CONTEXT, req).setupForward(req, res, p, skin); } public PortalService getPortalService() { return portalService; } public void setPortalService(PortalService portalService) { this.portalService = portalService; } protected Templates createTemplate() throws IOException, TransformerConfigurationException { // TODO Update default trasformer path to use neo transformer when available String transformerPath = getDefaultTransformerPath(); return createTemplate(transformerPath); } protected Templates createTemplate(String transformerPath) throws IOException, TransformerConfigurationException { return createTemplate(getPortalWebappResourceManager().getResourceAsStream(transformerPath)); } protected Templates createTemplate(URL url) throws IOException, TransformerConfigurationException { InputStream stream = url.openStream(); String urlPath = url.toString(); String systemId = urlPath.substring(0, urlPath.lastIndexOf('/') + 1); Templates templates = TransformerFactory.newInstance().newTemplates( new StreamSource(stream, systemId)); return templates; } protected Templates createTemplate(InputStream stream) throws IOException, TransformerConfigurationException { Templates templates = TransformerFactory.newInstance().newTemplates( new StreamSource(stream)); return templates; } public String getDefaultTransformerPath() { return defaultTransformerPath; } public void setDefaultTransformerPath(String defaultTransformerPath) { this.defaultTransformerPath = defaultTransformerPath; } public Map<String, Templates> getTemplates() { return templates; } public void setTemplates(Map<String, Templates> templates) { this.templates = templates; } public Map<String, String> getTransformerPaths() { return transformerPaths; } public void setTransformerPaths(Map<String, String> transformerPaths) { this.transformerPaths = transformerPaths; } public WebappResourceManager getLibraryWebappResourceManager() { if (libraryWebappResourceManager == null) { libraryWebappResourceManager = (WebappResourceManager) ComponentManager.get("org.sakaiproject.webapp.api.WebappResourceManager.library"); } return libraryWebappResourceManager; } public void setLibraryWebappResourceManager(WebappResourceManager libraryWebappResourceManager) { this.libraryWebappResourceManager = libraryWebappResourceManager; } public WebappResourceManager getPortalWebappResourceManager() { return portalWebappResourceManager; } public void setPortalWebappResourceManager(WebappResourceManager portalWebappResourceManager) { this.portalWebappResourceManager = portalWebappResourceManager; } public boolean isCacheTemplates() { return cacheTemplates; } public void setCacheTemplates(boolean cacheTemplates) { this.cacheTemplates = cacheTemplates; } public URIResolver getLibraryServletResolver() { if (libraryServletResolver == null) { libraryServletResolver = new ServletResourceUriResolver(getLibraryWebappResourceManager()); } return libraryServletResolver; } public void setLibraryServletResolver(URIResolver libraryServletResolver) { this.libraryServletResolver = libraryServletResolver; } }