Package ch.entwine.weblounge.common.impl.content.page

Source Code of ch.entwine.weblounge.common.impl.content.page.PageletRendererImpl

/*
*  Weblounge: Web Content Management System
*  Copyright (c) 2003 - 2011 The Weblounge Team
*  http://entwinemedia.com/weblounge
*
*  This program is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser General Public License
*  as published by the Free Software Foundation; either version 2
*  of the License, or (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU Lesser General Public License for more details.
*
*  You should have received a copy of the GNU Lesser General Public License
*  along with this program; if not, write to the Free Software Foundation
*  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

package ch.entwine.weblounge.common.impl.content.page;

import static ch.entwine.weblounge.common.site.Environment.Any;

import ch.entwine.weblounge.common.content.RenderException;
import ch.entwine.weblounge.common.content.page.HTMLHeadElement;
import ch.entwine.weblounge.common.content.page.Link;
import ch.entwine.weblounge.common.content.page.PagePreviewMode;
import ch.entwine.weblounge.common.content.page.PageletRenderer;
import ch.entwine.weblounge.common.content.page.Script;
import ch.entwine.weblounge.common.impl.util.config.ConfigurationUtils;
import ch.entwine.weblounge.common.impl.util.xml.XPathHelper;
import ch.entwine.weblounge.common.request.CacheTag;
import ch.entwine.weblounge.common.request.RequestFlavor;
import ch.entwine.weblounge.common.request.WebloungeRequest;
import ch.entwine.weblounge.common.request.WebloungeResponse;
import ch.entwine.weblounge.common.site.Environment;
import ch.entwine.weblounge.common.site.Module;
import ch.entwine.weblounge.common.site.Site;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;

import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;

/**
* This renderer implements a pagelet renderer that is backed by a Java Server
* Page.
*/
public class PageletRendererImpl extends AbstractRenderer implements PageletRenderer {

  /** The logging facility */
  private final Logger logger = LoggerFactory.getLogger(PageletRendererImpl.class);

  /** The editor url */
  protected URL editor = null;

  /** The defining module */
  protected Module module = null;

  /** The site */
  protected Site site = null;

  /** The preview mode */
  protected PagePreviewMode previewMode = PagePreviewMode.None;

  /**
   * Creates a new page template.
   */
  public PageletRendererImpl() {
    addFlavor(RequestFlavor.HTML);
  }

  /**
   * Creates a new page template with the given identifier.
   *
   * @param identifier
   *          the template identifier
   */
  public PageletRendererImpl(String identifier) {
    this(identifier, null);
  }

  /**
   * Creates a new page template that is backed by a Java Server Page located at
   * <code>url</code>.
   *
   * @param identifier
   *          the template identifier
   * @param url
   *          the renderer url
   */
  public PageletRendererImpl(String identifier, URL url) {
    super(identifier, url);
    addFlavor(RequestFlavor.HTML);
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.page.PageletRenderer#setModule(ch.entwine.weblounge.common.site.Module)
   */
  public void setModule(Module module) {
    if (module == null)
      throw new IllegalArgumentException("Module must not be null");
    this.module = module;
    this.site = module.getSite();
    for (HTMLHeadElement htmlHead : headers) {
      htmlHead.setSite(site);
      htmlHead.setModule(module);
    }
    if (!Any.equals(environment)) {
      processURLTemplates(environment);
    }
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.impl.content.GeneralComposeable#setEnvironment(ch.entwine.weblounge.common.site.Environment)
   */
  @Override
  public void setEnvironment(Environment environment) {
    if (environment == null)
      throw new IllegalArgumentException("Environment must not be null");

    // Is there anything we need to be doing?
    if (!environment.equals(this.environment) && module != null) {
      logger.debug("Processing url templates of {} with environment {}", this, environment);
      processURLTemplates(environment);
    }

    super.setEnvironment(environment);
  }

  /**
   * Processes both renderer and editor url by replacing templates in their
   * paths with real values from the actual module.
   *
   * @param environment
   *          the environment
   *
   * @return <code>false</code> if the paths don't end up being real urls,
   *         <code>true</code> otherwise
   */
  private boolean processURLTemplates(Environment environment) {
    if (module == null)
      throw new IllegalStateException("Module is null");
    if (module.getSite() == null)
      throw new IllegalArgumentException("Site is null");

    // Process the renderer URL
    for (Map.Entry<String, URL> entry : renderers.entrySet()) {
      URL renderer = entry.getValue();
      String rendererURL = ConfigurationUtils.processTemplate(renderer.toExternalForm(), module, environment);
      try {
        renderer = new URL(rendererURL);
        renderers.put(entry.getKey(), renderer);
      } catch (MalformedURLException e) {
        logger.warn("Renderer url {} of pagelet {} is malformed", rendererURL, this);
        return false;
      }
    }

    // Process the editor URL
    if (editor != null) {
      String editorURL = ConfigurationUtils.processTemplate(editor.toExternalForm(), module, environment);
      try {
        editor = new URL(editorURL);
      } catch (MalformedURLException e) {
        logger.warn("Editor url {} of pagelet {} is malformed", editorURL, this);
        return false;
      }
    }

    // Process the head elements (scripts and stylesheet includes)
    for (HTMLHeadElement headElement : headers) {
      headElement.setEnvironment(environment);
    }

    return true;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.impl.content.GeneralComposeable#addHTMLHeader(ch.entwine.weblounge.common.content.page.HTMLHeadElement)
   */
  @Override
  public void addHTMLHeader(HTMLHeadElement header) {
    if (module != null) {
      if (module != null)
        header.setModule(module);
      if (site != null)
        header.setSite(site);
      if (!Any.equals(environment))
        header.setEnvironment(environment);
    }
    super.addHTMLHeader(header);
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.page.PageletRenderer#getModule()
   */
  public Module getModule() {
    return module;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.page.PageletRenderer#setPreviewMode(ch.entwine.weblounge.common.content.Pagelet.PagePreviewMode)
   */
  public void setPreviewMode(PagePreviewMode mode) {
    this.previewMode = mode;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.page.PageletRenderer#getPreviewMode()
   */
  public PagePreviewMode getPreviewMode() {
    return previewMode;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.impl.content.page.AbstractRenderer#setRenderer(java.net.URL)
   */
  @Override
  public void setRenderer(URL renderer) {
    super.setRenderer(renderer);
    if (!Any.equals(environment) && module != null)
      processURLTemplates(environment);
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.impl.content.page.AbstractRenderer#getRenderer()
   */
  @Override
  public URL getRenderer() {
    return getRenderer(RendererType.Page.toString());
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.impl.content.page.AbstractRenderer#getRenderer(java.lang.String)
   */
  @Override
  public URL getRenderer(String type) {
    return super.getRenderer(type);
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.page.PageletRenderer#setEditor(java.net.URL)
   */
  public void setEditor(URL editor) {
    this.editor = editor;
    if (!Any.equals(environment) && module != null)
      processURLTemplates(environment);
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.page.PageletRenderer#getEditor()
   */
  public URL getEditor() {
    return editor;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.Renderer#render(ch.entwine.weblounge.common.request.WebloungeRequest,
   *      ch.entwine.weblounge.common.request.WebloungeResponse)
   */
  public void render(WebloungeRequest request, WebloungeResponse response)
      throws RenderException {

    // Adjust revalidation and expiration time
    response.setClientRevalidationTime(getClientRevalidationTime());
    response.setCacheExpirationTime(getCacheExpirationTime());

    // Add cache support
    response.addTag(CacheTag.Module, getModule().getIdentifier());
    response.addTag(CacheTag.Renderer, getIdentifier());

    URL renderer = renderers.get(RendererType.Page.toString().toLowerCase());
    includeJSP(request, response, renderer);
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.page.PageletRenderer#renderAsEditor(ch.entwine.weblounge.common.request.WebloungeRequest,
   *      ch.entwine.weblounge.common.request.WebloungeResponse)
   */
  public void renderAsEditor(WebloungeRequest request,
      WebloungeResponse response) throws RenderException {
    includeJSP(request, response, editor);
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.impl.content.GeneralComposeable#hashCode()
   */
  @Override
  public int hashCode() {
    return super.hashCode();
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.impl.content.GeneralComposeable#equals(java.lang.Object)
   */
  @Override
  public boolean equals(Object o) {
    if (!(o instanceof PageletRenderer))
      return false;
    PageletRenderer r = (PageletRenderer) o;
    if (module != null && !module.equals(r.getModule()))
      return false;
    return super.equals(o);
  }

  /**
   * Initializes this pagelet renderer from an XML node that was generated using
   * {@link #toXml()}.
   * <p>
   * To speed things up, you might consider using the second signature that uses
   * an existing <code>XPath</code> instance instead of creating a new one.
   *
   * @param node
   *          the pagelet renderer node
   * @throws IllegalStateException
   *           if the pagelet renderer cannot be parsed
   * @see #fromXml(Node, XPath)
   * @see #toXml()
   */
  public static PageletRenderer fromXml(Node node) throws IllegalStateException {
    XPath xpath = XPathFactory.newInstance().newXPath();
    return fromXml(node, xpath);
  }

  /**
   * Initializes this pagelet renderer from an XML node that was generated using
   * {@link #toXml()}.
   *
   * @param node
   *          the pagelet renderer node
   * @param xpath
   *          the xpath processor
   * @throws IllegalStateException
   *           if the pagelet renderer cannot be parsed
   * @see #fromXml(Node)
   * @see #toXml()
   */
  public static PageletRenderer fromXml(Node node, XPath xpath)
      throws IllegalStateException {

    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

    // Identifier
    String id = XPathHelper.valueOf(node, "@id", xpath);
    if (id == null)
      throw new IllegalStateException("Missing id in page template definition");

    // Class
    String className = XPathHelper.valueOf(node, "m:class", xpath);

    // Create the pagelet renderer
    PageletRenderer renderer = null;
    if (className != null) {
      Class<? extends PageletRenderer> c = null;
      try {
        c = (Class<? extends PageletRenderer>) classLoader.loadClass(className);
        renderer = c.newInstance();
        renderer.setIdentifier(id);
      } catch (ClassNotFoundException e) {
        throw new IllegalStateException("Implementation " + className + " for pagelet renderer '" + id + "' not found", e);
      } catch (InstantiationException e) {
        throw new IllegalStateException("Error instantiating impelementation " + className + " for pagelet renderer '" + id + "'", e);
      } catch (IllegalAccessException e) {
        throw new IllegalStateException("Access violation instantiating implementation " + className + " for pagelet renderer '" + id + "'", e);
      } catch (Throwable t) {
        throw new IllegalStateException("Error loading implementation " + className + " for pagelet renderer '" + id + "'", t);
      }
    } else {
      renderer = new PageletRendererImpl();
      renderer.setIdentifier(id);
    }

    // Renderer url
    NodeList rendererUrlNodes = XPathHelper.selectList(node, "m:renderer", xpath);
    if (rendererUrlNodes.getLength() == 0)
      throw new IllegalStateException("Missing renderer in page template definition");
    for (int i = 0; i < rendererUrlNodes.getLength(); i++) {
      Node rendererUrlNode = rendererUrlNodes.item(i);
      URL rendererUrl = null;
      Node typeNode = rendererUrlNode.getAttributes().getNamedItem("type");
      String type = (typeNode != null) ? typeNode.getNodeValue() : RendererType.Page.toString();
      try {
        rendererUrl = new URL(rendererUrlNode.getFirstChild().getNodeValue());
        renderer.addRenderer(rendererUrl, type);
      } catch (MalformedURLException e) {
        throw new IllegalStateException("Malformed renderer url in page template definition: " + rendererUrlNode);
      }
    }

    // Composeable
    renderer.setComposeable("true".equals(XPathHelper.valueOf(node, "@composeable", xpath)));

    // Preview mode
    String previewMode = XPathHelper.valueOf(node, "m:preview", xpath);
    if (previewMode != null)
      renderer.setPreviewMode(PagePreviewMode.parse(previewMode));

    // Editor url
    String editorUrlNode = XPathHelper.valueOf(node, "m:editor", xpath);
    try {
      if (editorUrlNode != null) {
        URL editorUrl = new URL(editorUrlNode);
        renderer.setEditor(editorUrl);
      }
    } catch (MalformedURLException e) {
      throw new IllegalStateException("Malformed editor url in page template definition: " + editorUrlNode);
    }

    // client revalidation time
    String recheck = XPathHelper.valueOf(node, "m:recheck", xpath);
    if (recheck != null) {
      try {
        renderer.setClientRevalidationTime(ConfigurationUtils.parseDuration(recheck));
      } catch (NumberFormatException e) {
        throw new IllegalStateException("The pagelet renderer revalidation time is malformed: '" + recheck + "'");
      } catch (IllegalArgumentException e) {
        throw new IllegalStateException("The pagelet renderer revalidation time is malformed: '" + recheck + "'");
      }
    }

    // cache expiration time
    String valid = XPathHelper.valueOf(node, "m:valid", xpath);
    if (valid != null) {
      try {
        renderer.setCacheExpirationTime(ConfigurationUtils.parseDuration(valid));
      } catch (NumberFormatException e) {
        throw new IllegalStateException("The pagelet renderer valid time is malformed: '" + valid + "'", e);
      } catch (IllegalArgumentException e) {
        throw new IllegalStateException("The pagelet renderer valid time is malformed: '" + valid + "'", e);
      }
    }

    // name
    String name = XPathHelper.valueOf(node, "m:name", xpath);
    renderer.setName(name);

    // scripts
    NodeList scripts = XPathHelper.selectList(node, "m:includes/m:script", xpath);
    for (int i = 0; i < scripts.getLength(); i++) {
      renderer.addHTMLHeader(ScriptImpl.fromXml(scripts.item(i)));
    }

    // links
    NodeList includes = XPathHelper.selectList(node, "m:includes/m:link", xpath);
    for (int i = 0; i < includes.getLength(); i++) {
      renderer.addHTMLHeader(LinkImpl.fromXml(includes.item(i)));
    }

    return renderer;
  }

  /**
   * Returns an XML representation of this renderer.
   *
   * @return the xml representation
   */
  public String toXml() {
    StringBuffer buf = new StringBuffer();
    buf.append("<pagelet");
    buf.append(" id=\"").append(identifier).append("\"");
    buf.append(" composeable=\"").append(composeable).append("\"");
    buf.append(">");

    // Names
    if (StringUtils.isNotBlank(name)) {
      buf.append("<name><![CDATA[");
      buf.append(name);
      buf.append("]]></name>");
    }

    // Renderer class
    if (!this.getClass().equals(PageletRendererImpl.class))
      buf.append("<class>").append(getClass().getName()).append("</class>");

    // Renderer url
    for (Map.Entry<String, URL> entry : renderers.entrySet()) {
      if (renderers.size() > 1)
        buf.append("<renderer type=\"").append(entry.getKey()).append("\">");
      else
        buf.append("<renderer>");
      buf.append(entry.getValue().toExternalForm()).append("</renderer>");
    }

    // Editor url
    if (editor != null)
      buf.append("<editor>").append(editor.toExternalForm()).append("</editor>");

    // Recheck time
    if (clientRevalidationTime >= 0) {
      buf.append("<recheck>");
      buf.append(ConfigurationUtils.toDuration(clientRevalidationTime));
      buf.append("</recheck>");
    }

    // Valid time
    if (cacheExpirationTime >= 0) {
      buf.append("<valid>");
      buf.append(ConfigurationUtils.toDuration(cacheExpirationTime));
      buf.append("</valid>");
    }

    // Preview
    if (!previewMode.equals(PagePreviewMode.None)) {
      buf.append("<preview>");
      buf.append(previewMode.toString().toLowerCase());
      buf.append("</preview>");
    }

    // Includes
    if (getHTMLHeaders().length > 0) {
      buf.append("<includes>");
      for (HTMLHeadElement header : getHTMLHeaders()) {
        if (header instanceof Link)
          buf.append(header.toXml());
      }
      for (HTMLHeadElement header : getHTMLHeaders()) {
        if (header instanceof Script)
          buf.append(header.toXml());
      }
      buf.append("</includes>");
    }

    buf.append("</pagelet>");
    return buf.toString();
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.impl.content.GeneralComposeable#toString()
   */
  @Override
  public String toString() {
    return module.getIdentifier() + "/" + identifier;
  }

}
TOP

Related Classes of ch.entwine.weblounge.common.impl.content.page.PageletRendererImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.