Package com.liferay.faces.bridge.renderkit.html_basic

Source Code of com.liferay.faces.bridge.renderkit.html_basic.ResourceRendererBridgeImpl

/**
* Copyright (c) 2000-2014 Liferay, Inc. All rights reserved.
*
* This library 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.1 of the License, or (at your option)
* any later version.
*
* This library 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.
*/
package com.liferay.faces.bridge.renderkit.html_basic;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

import javax.faces.component.StateHolder;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.ComponentSystemEvent;
import javax.faces.event.ComponentSystemEventListener;
import javax.faces.event.ListenerFor;
import javax.faces.event.PostAddToViewEvent;
import javax.faces.render.Renderer;
import javax.faces.render.RendererWrapper;

import com.liferay.faces.util.application.ComponentResource;
import com.liferay.faces.util.application.ComponentResourceFactory;
import com.liferay.faces.util.factory.FactoryExtensionFinder;
import com.liferay.faces.util.logging.Logger;
import com.liferay.faces.util.logging.LoggerFactory;


/**
* This class serves as a wrapper around the renderer provided by the JSF runtime (Mojarra, MyFaces) for either the
* h:outputScript or h:outputStylesheet components. The main purpose of wrapping the renderer is to provide a way for
* the bridge to keep track of which resources are being added to the <head>...</head> section of the portal
* page.
*
* @author  Neil Griffin
*/
@ListenerFor(systemEventClass = PostAddToViewEvent.class)
public class ResourceRendererBridgeImpl extends RendererWrapper implements ComponentSystemEventListener, StateHolder {

  // Logger
  private static final Logger logger = LoggerFactory.getLogger(ResourceRendererBridgeImpl.class);

  // Private Data Members
  private boolean transientFlag;
  private Renderer wrappedRenderer;

  /**
   * This zero-arg constructor is required by the {@link javax.faces.component.StateHolderSaver} class during the
   * RESTORE_VIEW phase of the JSF lifecycle. The reason why this class is involved in restoring state is because the
   * {@link javax.faces.component.UIComponent.ComponentSystemEventListenerAdapter} implements {@link
   * javax.faces.component.StateHolder} and will attempt to restore the state of any class in the restored view that
   * implements {@link ComponentSystemEventListener}. It does this first by instantiating the class with a zero-arg
   * constructor, and then calls the {@link #restoreState(FacesContext, Object)} method.
   */
  public ResourceRendererBridgeImpl() {
    // Defer initialization of wrappedRenderer until restoreState(FacesContext, Object) is called.
  }

  public ResourceRendererBridgeImpl(Renderer renderer) {
    this.wrappedRenderer = renderer;
  }

  @Override
  public void encodeEnd(FacesContext facesContext, UIComponent uiComponent) throws IOException {

    ComponentResourceFactory componentResourceFactory = (ComponentResourceFactory) FactoryExtensionFinder
      .getFactory(ComponentResourceFactory.class);
    ComponentResource componentResource = componentResourceFactory.getComponentResource(uiComponent);
    String resourceId = componentResource.getId();

    // Determine whether or not the specified resource is already present in the <head> section of the portal page.
    HeadManagedBean headManagedBean = HeadManagedBean.getInstance(facesContext);

    Set<String> headResourceIdsFromManagedBean = null;

    if (headManagedBean == null) {

      // Since the HeadManagedBean can't be found, this request is likely executing in a JSP environment.
      headResourceIdsFromManagedBean = new HashSet<String>();
    }
    else {
      headResourceIdsFromManagedBean = headManagedBean.getHeadResourceIds();
    }

    boolean alreadyPresentInPortalPageHead = headResourceIdsFromManagedBean.contains(resourceId);

    // If the specified resource is NOT already in the <head> section of the portal page, then
    if (!alreadyPresentInPortalPageHead) {

      boolean ajaxRequest = facesContext.getPartialViewContext().isAjaxRequest();

      // If this is taking place during an Ajax request, then:
      if (ajaxRequest) {

        // Set a custom response writer that knows how to remove double-encoded ampersands from URLs.
        ResponseWriter responseWriter = facesContext.getResponseWriter();
        facesContext.setResponseWriter(new ResponseWriterResourceImpl(responseWriter));

        // Ask the wrapped renderer to encode the script to a custom ResponseWriter
        super.encodeEnd(facesContext, uiComponent);

        // Restore the original response writer.
        facesContext.setResponseWriter(responseWriter);
      }

      // Otherwise:
      else {

        // Ask the wrapped renderer to encode the script to a custom ResponseWriter
        super.encodeEnd(facesContext, uiComponent);

        // If the h:head part of the component tree is being rendered, then
        if (facesContext.getResponseWriter() instanceof HeadResponseWriter) {

          // Mark the resource as having been added to the head.
          headResourceIdsFromManagedBean.add(resourceId);

          logger.debug("Marking resource resourceId=[{0}] as being present in the head", resourceId);
        }
      }
    }
  }

  /**
   * Since the Mojarra {@link com.sun.faces.renderkit.html_basic.ScriptStyleBaseRenderer} class implements {@link
   * ComponentSystemEventListener}, this class must implement that interface too, since this is a wrapper type of
   * class. Mojarra uses this method to intercept {@link PostAddToViewEvent} in order to add script and link resources
   * to the head (if the target attribute has a value of "head").
   */
  public void processEvent(ComponentSystemEvent event) throws AbortProcessingException {

    // If the wrapped renderer has the ability to listen to component system events, then invoke the event
    // processing on the wrapped renderer. This is necessary when wrapping the Mojarra ScriptRenderer or
    // StylesheetRenderer because they extend ScriptStyleBaseRenderer which attempts to add the component
    // associated with the specified event as a resource on the view root.
    if (wrappedRenderer instanceof ComponentSystemEventListener) {
      ComponentSystemEventListener wrappedListener = (ComponentSystemEventListener) wrappedRenderer;
      wrappedListener.processEvent(event);
    }
    else {
      logger.debug("Wrapped renderer=[{0}] does not implement ComponentSystemEventListener", wrappedRenderer);
    }
  }

  public void restoreState(FacesContext facesContext, Object state) {

    if (wrappedRenderer == null) {

      try {
        String wrappedRendererClassName = (String) state;
        Class<?> wrappedRendererClass = Class.forName(wrappedRendererClassName);
        wrappedRenderer = (Renderer) wrappedRendererClass.newInstance();
      }
      catch (Exception e) {
        logger.error(e);
      }
    }
  }

  public Object saveState(FacesContext facesContext) {
    return wrappedRenderer.getClass().getName();
  }

  public boolean isTransient() {
    return transientFlag;
  }

  public void setTransient(boolean newTransientValue) {
    this.transientFlag = newTransientValue;
  }

  @Override
  public Renderer getWrapped() {
    return wrappedRenderer;
  }
}
TOP

Related Classes of com.liferay.faces.bridge.renderkit.html_basic.ResourceRendererBridgeImpl

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.