Package ch.entwine.weblounge.common.impl.site

Source Code of ch.entwine.weblounge.common.impl.site.HTMLActionSupport

/*
*  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.site;

import ch.entwine.weblounge.common.content.ResourceURI;
import ch.entwine.weblounge.common.content.page.Composer;
import ch.entwine.weblounge.common.content.page.HTMLHeadElement;
import ch.entwine.weblounge.common.content.page.HTMLInclude;
import ch.entwine.weblounge.common.content.page.Link;
import ch.entwine.weblounge.common.content.page.Page;
import ch.entwine.weblounge.common.content.page.PageTemplate;
import ch.entwine.weblounge.common.content.page.Pagelet;
import ch.entwine.weblounge.common.content.page.PageletRenderer;
import ch.entwine.weblounge.common.content.page.Script;
import ch.entwine.weblounge.common.impl.content.page.PageURIImpl;
import ch.entwine.weblounge.common.impl.util.config.ConfigurationUtils;
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.ActionException;
import ch.entwine.weblounge.common.site.HTMLAction;
import ch.entwine.weblounge.common.site.I18nDictionary;
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 java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;

/**
* This class is the default implementation for an <code>HTMLAction</code>. The
* implementations of the various <code>startXYZ</code> methods are implemented
* such that they leave it to the target page to render the stuff.
* <p>
* <b>Note:</b> Be aware of the fact that actions are pooled, so make sure to
* implement the <code>activate()</code> and <code>passivate()</code> method
* accordingly and include the respective super implementations.
*/
public class HTMLActionSupport extends ActionSupport implements HTMLAction {

  /** Logging facility */
  protected static final Logger logger = LoggerFactory.getLogger(HTMLActionSupport.class);

  /** The default path to render on */
  protected String targetPath = null;

  /** The page uri, deducted from targetPath */
  protected ResourceURI pageURI = null;

  /** The default page template id */
  protected String defaultTemplateId = null;

  /** The stage renderer id */
  protected String stageRendererId = null;

  /** The page template */
  protected PageTemplate defaultTemplate = null;

  /** The page template */
  protected PageTemplate template = null;

  /** The underlying page */
  protected Page page = null;

  /** The renderer used for this request */
  protected PageletRenderer stageRenderer = null;

  /** The information messages */
  protected List<String> infoMessages = null;

  /** The warning messages */
  protected List<String> warningMessages = null;

  /** The error messages */
  protected List<String> errorMessages = null;

  /** Flag to indicate that output has been written to the client */
  protected boolean outputStarted = false;

  /**
   * Creates a new action implementation that directly supports the generation
   * of <code>HTML</code> pages.
   */
  public HTMLActionSupport() {
    this(null);
  }

  /**
   * Creates a new action implementation that directly supports the generation
   * of <code>HTML</code> pages.
   * <p>
   * When passing in <code>renderer</code>, the action's default behavior will
   * be to write the renderer to the stage.
   *
   * @param renderer
   *          the renderer identifier
   */
  public HTMLActionSupport(String renderer) {
    addFlavor(RequestFlavor.HTML);
    stageRendererId = renderer;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.site.Action#passivate()
   */
  @Override
  public void passivate() {
    super.passivate();
    page = null;
    template = null;
    infoMessages = null;
    warningMessages = null;
    errorMessages = null;
    outputStarted = false;
  }

  /**
   * Sets the associated site if this is a site related renderer configuration.
   *
   * @param site
   *          the associated site
   */
  @Override
  public void setSite(Site site) {
    super.setSite(site);
    if (site == null)
      return;

    if (targetPath != null)
      this.pageURI = new PageURIImpl(site, targetPath);
    if (defaultTemplateId != null && defaultTemplate == null)
      setDefaultTemplate(site.getTemplate(defaultTemplateId));
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.impl.site.ActionSupport#setModule(ch.entwine.weblounge.common.site.Module)
   */
  @Override
  public void setModule(Module module) {
    super.setModule(module);
    if (StringUtils.isNotBlank(stageRendererId)) {
      this.stageRenderer = getModule().getRenderer(stageRendererId);
      if (this.stageRenderer == null) {
        logger.warn("Stage renderer '{}' for action {} not found", stageRendererId, this);
      }
    }
  }

  /**
   * Sets the page that is used to do the action's rendering.
   *
   * @param page
   *          the page
   */
  public void setPage(Page page) {
    this.page = page;
  }

  /**
   * Returns the page that is used to do the action's rendering.
   *
   * @return the target page
   */
  public Page getPage() {
    return page;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.site.Action#setPageURI(ch.entwine.weblounge.common.content.ResourceURI)
   */
  public void setPageURI(ResourceURI uri) {
    this.pageURI = uri;
  }

  /**
   * Convenience method used to be able to define the target URI without having
   * access to the <code>Site</code> yet that will allow to set the uri as an
   * object of type <code>PageURI</code>.
   *
   * @param uri
   *          the target path
   * @see #setPageURI(ResourceURI)
   */
  void setPageURI(String uri) {
    this.targetPath = uri;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.site.Action#getPageURI()
   */
  public ResourceURI getPageURI() {
    if (pageURI == null && site != null && StringUtils.isNotBlank(targetPath)) {
      pageURI = new PageURIImpl(site, targetPath);
    }
    return pageURI;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.site.HTMLAction#setDefaultTemplate(ch.entwine.weblounge.common.content.page.PageTemplate)
   */
  public void setDefaultTemplate(PageTemplate template) {
    this.defaultTemplate = template;
  }

  /**
   * Convenience method used to be able to define the target template without
   * having access to the <code>Site</code> yet that will allow to set the
   * template as an object of type <code>PageTemplate</code>.
   *
   * @param template
   *          the template identifier
   * @see #setTemplate(PageTemplate)
   */
  void setDefaultTemplate(String template) {
    this.defaultTemplateId = template;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.site.HTMLAction#getDefaultTemplate()
   */
  public PageTemplate getDefaultTemplate() {
    if (defaultTemplate != null)
      return defaultTemplate;

    // At configuration time, only the template is known
    if (defaultTemplateId != null) {
      defaultTemplate = site.getTemplate(defaultTemplateId);
      return defaultTemplate;
    }

    return null;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.site.HTMLAction#setDefaultTemplate(ch.entwine.weblounge.common.content.page.PageTemplate)
   */
  public void setTemplate(PageTemplate template) {
    this.template = template;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.site.Action#getTemplate()
   */
  public PageTemplate getTemplate() {
    return template;
  }

  /**
   * Sets the renderer that is used to renderer the <code>stage</code> composer
   * when implementers don't overwrite
   * {@link #startStage(WebloungeRequest, WebloungeResponse, Composer)} and
   * {@link #startComposer(WebloungeRequest, WebloungeResponse, Composer)}.
   *
   * @param renderer
   *          the stage renderer
   */
  public void setStageRenderer(PageletRenderer renderer) {
    this.stageRendererId = (renderer != null) ? renderer.getIdentifier() : null;
    this.stageRenderer = renderer;
  }

  /**
   * Returns the renderer that is used to renderer the <code>stage</code>
   * composer when implementers don't overwrite
   * {@link #startStage(WebloungeRequest, WebloungeResponse, Composer)} and
   * {@link #startComposer(WebloungeRequest, WebloungeResponse, Composer)}.
   *
   * @return the renderer
   */
  public PageletRenderer getStageRenderer() {
    if (stageRenderer == null) {
      if (StringUtils.isNotBlank(stageRendererId)) {
        if (module == null) {
          throw new IllegalStateException("Module was not set");
        }
        stageRenderer = getModule().getRenderer(stageRendererId);
        if (stageRenderer == null) {
          logger.warn("Stage renderer '{}' not found in module '{}'", stageRendererId, module.getIdentifier());
        }
      }
    }
    return stageRenderer;
  }

  /**
   * Returns <code>true</code> if <code>composer</code> equals the stage of the
   * current renderer.
   *
   * @param composer
   *          the composer to test
   * @param request
   *          the request
   * @return <code>true</code> if <code>composer</code> is the main stage
   */
  @Override
  protected boolean isStage(String composer, WebloungeRequest request) {
    if (composer == null)
      throw new IllegalArgumentException("Composer may not be null!");

    String stage = PageTemplate.DEFAULT_STAGE;
    PageTemplate template = (PageTemplate) request.getAttribute(WebloungeRequest.TEMPLATE);
    if (template != null)
      stage = template.getStage();
    return composer.equalsIgnoreCase(stage);
  }

  /**
   * This implementation always returns
   * {@link ch.entwine.weblounge.common.site.Action#EVAL_REQUEST} and simply
   * sets the content type on the response to
   * <code>text/html;charset=utf-8</code>. This means that subclasses should
   * either overwrite this method to specify a different encoding or make sure
   * that everything that is written to the response is encoded to
   * <code>utf-8</code>.
   *
   * @param request
   *          the servlet request
   * @param response
   *          the servlet response
   * @return {@link ch.entwine.weblounge.common.site.Action#EVAL_REQUEST}
   */
  @Override
  public int startResponse(WebloungeRequest request, WebloungeResponse response)
      throws ActionException {
    String characterEncoding = response.getCharacterEncoding();
    if (StringUtils.isNotBlank(characterEncoding))
      response.setContentType("text/html;charset=" + characterEncoding.toLowerCase());
    else
      response.setContentType("text/html");
    outputStarted = true;
    return EVAL_REQUEST;
  }

  /**
   * {@inheritDoc}
   * <p>
   * This implementation asks the action to return the include headers
   * <code>&lt;script&gt;</code> and <code>&lt;link&gt;</code> by calling
   * {@link #getHTMLHeaders()} and writes them to the response.
   * <p>
   * Since this implementation collects all of the includes that are needed to
   * render the page by iterating over the included elements, it returns
   * {@link ch.entwine.weblounge.common.site.HTMLAction#SKIP_HEADER} to tell the
   * tag implementation that no further work is needed.
   *
   * @see ch.entwine.weblounge.common.site.HTMLAction#startHeader(ch.entwine.weblounge.common.request.WebloungeRequest,
   *      ch.entwine.weblounge.common.request.WebloungeResponse)
   */
  public int startHeader(WebloungeRequest request, WebloungeResponse response)
      throws IOException, ActionException {
    return EVAL_HEADER;
  }

  /**
   * This method always returns
   * {@link ch.entwine.weblounge.common.site.HTMLAction#EVAL_COMPOSER} and
   * therefore leaves rendering to the actual content of the composer. This
   * means that if this action is rendered on an existing page, a call to
   * {@link #startPagelet(WebloungeRequest, WebloungeResponse, String, ch.entwine.weblounge.common.content.page.Pagelet)}
   * for each of them will be issued.
   *
   * @param request
   *          the request object
   * @param response
   *          the response object
   * @return <code>EVAL_COMPOSER</code>
   * @see ch.entwine.weblounge.common.site.HTMLAction#startStage(ch.entwine.weblounge.api.request.WebloungeRequest,
   *      ch.entwine.weblounge.api.request.WebloungeResponse,
   *      ch.entwine.weblounge.common.content.page.Composer)
   */
  public int startStage(WebloungeRequest request, WebloungeResponse response,
      Composer composer) throws IOException, ActionException {
    if (stageRenderer != null) {
      include(request, response, stageRenderer, null);
      return SKIP_COMPOSER;
    }
    return EVAL_COMPOSER;
  }

  /**
   * This method always returns
   * {@link ch.entwine.weblounge.common.site.HTMLAction#EVAL_COMPOSER} and
   * therefore leaves rendering to the actual content of the composer. This
   * means that if this action is rendered on an existing page, a call to
   * {@link #startPagelet(WebloungeRequest, WebloungeResponse, String, ch.entwine.weblounge.common.content.page.Pagelet)}
   * for each of them will be issued.
   *
   * @param request
   *          the request object
   * @param response
   *          the response object
   * @return <code>EVAL_COMPOSER</code>
   * @see ch.entwine.weblounge.common.site.HTMLAction#startComposer(ch.entwine.weblounge.common.request.WebloungeRequest,
   *      ch.entwine.weblounge.common.request.WebloungeResponse,
   *      ch.entwine.weblounge.common.content.page.Composer)
   */
  public int startComposer(WebloungeRequest request,
      WebloungeResponse response, Composer composer) throws IOException,
      ActionException {
    return EVAL_COMPOSER;
  }

  /**
   * This method always returns
   * {@link ch.entwine.weblounge.common.site.HTMLAction#EVAL_PAGELET} and
   * therefore leaves rendering to the pagelet.
   *
   * @param request
   *          the request object
   * @param response
   *          the response object
   * @param pagelet
   *          the pagelet
   * @return <code>EVAL_PAGELET</code>
   * @see ch.entwine.weblounge.common.site.HTMLAction#startPagelet(ch.entwine.weblounge.common.request.WebloungeRequest,
   *      ch.entwine.weblounge.common.request.WebloungeResponse,
   *      ch.entwine.weblounge.common.content.page.Pagelet)
   */
  public int startPagelet(WebloungeRequest request, WebloungeResponse response,
      Pagelet pagelet) throws IOException, ActionException {
    return EVAL_PAGELET;
  }

  /**
   * Includes the given renderer with the request.
   *
   * @param request
   *          the request
   * @param response
   *          the response
   * @param renderer
   *          the renderer to include
   * @param pagelet
   *          the pagelet data
   * @throws ActionException
   *           if rendering the pagelet fails
   */
  @Override
  protected void include(WebloungeRequest request, WebloungeResponse response,
      PageletRenderer renderer, Pagelet pagelet) throws ActionException {
    if (renderer == null) {
      String msg = "Renderer to be included in action '" + this + "' on " + request.getUrl() + " was not found!";
      logger.error(msg);
      response.invalidate();
      return;
    }

    // Add the pagelet's header elements to the response
    for (HTMLHeadElement header : renderer.getHTMLHeaders()) {
      if (!HTMLInclude.Use.Editor.equals(header.getUse()))
        response.addHTMLHeader(header);
    }

    super.include(request, response, renderer, pagelet);
  }

  /**
   * Adds the message to the list of information messages.
   *
   * @param request
   *          the weblounge request
   * @param msg
   *          the message
   */
  protected void reportInfo(WebloungeRequest request, String msg) {
    reportInfo(request, msg, new Object[] {});
  }

  /**
   * Adds the message to the list of information messages.
   *
   * @param request
   *          the weblounge request
   * @param msg
   *          the message
   * @param arguments
   *          the list of arguments to incorporate into the message
   */
  protected void reportInfo(WebloungeRequest request, String msg,
      Object... arguments) {
    if (msg == null)
      throw new IllegalArgumentException("Message cannot be null");
    if (infoMessages == null) {
      infoMessages = new ArrayList<String>();
      request.setAttribute(HTMLAction.INFOS, infoMessages);
    }
    infoMessages.add(createMessage(request, msg, arguments));
  }

  /**
   * Returns <code>true</code> if info messages have been reported.
   *
   * @return <code>true</code> if there are info messages
   */
  protected boolean hasMessages() {
    return infoMessages == null || infoMessages.size() == 0;
  }

  /**
   * Adds the message to the list of warning messages.
   *
   * @param request
   *          the weblounge request
   * @param msg
   *          the warning message
   */
  protected void reportWarning(WebloungeRequest request, String msg) {
    reportWarning(request, msg, null, new Object[] {});
  }

  /**
   * Adds the message to the list of warning messages.
   *
   * @param request
   *          the weblounge request
   * @param msg
   *          the warning message
   * @param arguments
   *          the list of arguments to incorporate into the message
   */
  protected void reportWarning(WebloungeRequest request, String msg,
      Object... arguments) {
    if (msg == null)
      throw new IllegalArgumentException("Warning message cannot be null");
    if (warningMessages == null) {
      warningMessages = new ArrayList<String>();
      request.setAttribute(HTMLAction.WARNINGS, warningMessages);
    }
    warningMessages.add(createMessage(request, msg, arguments));
  }

  /**
   * Returns <code>true</code> if warning messages have been reported.
   *
   * @return <code>true</code> if there are warning messages
   */
  protected boolean hasWarnings() {
    return warningMessages == null || warningMessages.size() == 0;
  }

  /**
   * Adds the message to the list of error messages.
   *
   * @param msg
   *          the error message
   * @param request
   *          the weblounge request
   */
  protected void reportError(WebloungeRequest request, String msg) {
    reportError(request, msg, null, new Object[] {});
  }

  /**
   * Adds the message to the list of error messages.
   *
   * @param msg
   *          the error message
   * @param request
   *          the weblounge request
   * @param arguments
   *          the list of arguments to incorporate into the message
   */
  protected void reportError(WebloungeRequest request, String msg,
      Object... arguments) {
    if (msg == null)
      throw new IllegalArgumentException("Error message cannot be null");
    if (errorMessages == null) {
      errorMessages = new ArrayList<String>();
      request.setAttribute(HTMLAction.ERRORS, errorMessages);
    }
    errorMessages.add(createMessage(request, msg, arguments));
  }

  /**
   * Processes the message by first looking up its I18n translation and then
   * applying optional arguments using a {@link MessageFormat}.
   *
   * @param request
   *          the request
   * @param msg
   *          the message
   * @param args
   *          optional message arguments
   * @return the message
   */
  private String createMessage(WebloungeRequest request, String msg,
      Object... args) {
    I18nDictionary dictionary = request.getSite().getI18n();
    msg = dictionary.get(msg, request.getLanguage());
    if (args == null || args.length == 0)
      return msg;
    return MessageFormat.format(msg, args);
  }

  /**
   * Returns <code>true</code> if error messages have been reported.
   *
   * @return <code>true</code> if there are error messages
   */
  protected boolean hasErrors() {
    return errorMessages == null || errorMessages.size() == 0;
  }

  /**
   * {@inheritDoc}
   *
   * @see ch.entwine.weblounge.common.site.Action#toXml()
   */
  @Override
  public String toXml() {
    StringBuffer b = new StringBuffer();
    b.append("<action id=\"");
    b.append(identifier);
    b.append("\">");

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

    // class
    b.append("<class>").append(getClass().getName()).append("</class>");

    // mountpoint
    b.append("<mountpoint>").append(mountpoint).append("</mountpoint>");

    // pageuri
    if (pageURI != null)
      b.append("<page>").append(pageURI.getPath()).append("</page>");
    else if (targetPath != null)
      b.append("<page>").append(targetPath).append("</page>");

    // template
    if (template != null)
      b.append("<template>").append(template).append("</template>");
    else if (defaultTemplateId != null)
      b.append("<template>").append(defaultTemplateId).append("</template>");

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

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

    // Includes
    if (headers.size() > 0) {
      b.append("<includes>");
      for (HTMLHeadElement include : getHTMLHeaders()) {
        if (include instanceof Link)
          b.append(include.toXml());
      }
      for (HTMLHeadElement include : getHTMLHeaders()) {
        if (include instanceof Script)
          b.append(include.toXml());
      }
      b.append("</includes>");
    }

    // Options
    b.append(options.toXml());

    b.append("</action>");
    return b.toString();
  }

}
TOP

Related Classes of ch.entwine.weblounge.common.impl.site.HTMLActionSupport

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.