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

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

/*
*  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.PageTemplate;
import ch.entwine.weblounge.common.content.page.Script;
import ch.entwine.weblounge.common.impl.site.SiteImpl;
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.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.Iterator;
import java.util.Map;

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

/**
* This renderer implements a page template that is backed by a Java Server
* Page.
*/
public class PageTemplateImpl extends AbstractRenderer implements PageTemplate {

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

  /** Default composer for action output */
  protected String stage = DEFAULT_STAGE;

  /** Default page layout */
  protected String layout = null;

  /** Is this the default template? */
  protected boolean isDefault = false;

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

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

  /**
   * 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 PageTemplateImpl(String identifier, URL url) {
    super(identifier, url);
    addFlavor(RequestFlavor.HTML);
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.page.PageTemplate#setSite(ch.entwine.weblounge.common.site.Site)
   */
  public void setSite(Site site) {
    if (site == null)
      throw new IllegalArgumentException("Site must not be null");

    this.site = site;
    for (HTMLHeadElement htmlHead : headers) {
      htmlHead.setSite(site);
    }

    if (!Any.equals(environment)) {
      processURLTemplates(environment);
    }
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.page.PageTemplate#setStage(java.lang.String)
   */
  public void setStage(String stage) {
    this.stage = stage;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.page.PageTemplate#getStage()
   */
  public String getStage() {
    return stage;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.page.PageTemplate#getDefaultLayout()
   */
  public String getDefaultLayout() {
    return layout;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.page.PageTemplate#setDefaultLayout(java.lang.String)
   */
  public void setDefaultLayout(String layout) {
    this.layout = layout;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.page.PageTemplate#setDefault(boolean)
   */
  public void setDefault(boolean v) {
    isDefault = v;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.page.PageTemplate#isDefault()
   */
  public boolean isDefault() {
    return isDefault;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.content.page.PageTemplate#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.Renderer, getIdentifier());

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

  /**
   * {@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) {
    // This is to indicate that using the super implementation is sufficient
    return super.equals(o);
  }

  /**
   * Initializes this page template 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 page template node
   * @throws IllegalStateException
   *           if the page template cannot be parsed
   * @see #fromXml(Node, XPath)
   * @see #toXml()
   */
  public static PageTemplate fromXml(Node node) throws IllegalStateException {
    XPath xpath = XPathFactory.newInstance().newXPath();

    // Define the xml namespace
    xpath.setNamespaceContext(new NamespaceContext() {
      public String getNamespaceURI(String prefix) {
        return "ns".equals(prefix) ? SiteImpl.SITE_XMLNS : null;
      }

      public String getPrefix(String namespaceURI) {
        return null;
      }

      public Iterator<?> getPrefixes(String namespaceURI) {
        return null;
      }
    });

    return fromXml(node, xpath);
  }

  /**
   * Initializes this page template from an XML node that was generated using
   * {@link #toXml()}.
   *
   * @param node
   *          the page template node
   * @param xpath
   *          the xpath processor
   * @throws IllegalStateException
   *           if the page template cannot be parsed
   * @see #fromXml(Node)
   * @see #toXml()
   */
  public static PageTemplate 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, "class", xpath);

    // Renderer url
    URL rendererUrl = null;
    String rendererUrlNode = XPathHelper.valueOf(node, "ns:renderer", xpath);
    if (rendererUrlNode == null)
      throw new IllegalStateException("Missing renderer in page template definition");
    try {
      rendererUrl = new URL(rendererUrlNode);
    } catch (MalformedURLException e) {
      throw new IllegalStateException("Malformed renderer url in page template definition: " + rendererUrlNode);
    }

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

    // Composeable
    template.setComposeable(ConfigurationUtils.isTrue(XPathHelper.valueOf(node, "@composeable", xpath)));

    // Default
    template.setDefault(ConfigurationUtils.isTrue(XPathHelper.valueOf(node, "@default", xpath)));

    // Stage
    String stage = XPathHelper.valueOf(node, "ns:stage", xpath);
    if (stage != null)
      template.setStage(stage);

    // Layout
    String layout = XPathHelper.valueOf(node, "ns:layout", xpath);
    if (layout != null)
      template.setDefaultLayout(layout);

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

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

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

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

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

    return template;
  }

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

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

    // Renderer class
    if (!this.getClass().equals(PageTemplateImpl.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>");
    }

    // Stage name
    if (stage != null && !DEFAULT_STAGE.equals(stage))
      buf.append("<stage>").append(stage).append("</stage>");

    // Default page layout
    if (layout != null)
      buf.append("<layout>").append(layout).append("</layout>");

    // 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>");
    }

    // 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("</template>");
    return buf.toString();
  }

  /**
   * 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 (site == null)
      throw new IllegalStateException("Site cannot be null");

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

    // 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#setEnvironment(ch.entwine.weblounge.common.site.Environment)
   */
  @Override
  public void setEnvironment(Environment environment) {
    if (environment == null)
      throw new IllegalArgumentException("Environment cannot be null");

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

    super.setEnvironment(environment);
  }

}
TOP

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

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.