Package org.ajax4jsf.context

Source Code of org.ajax4jsf.context.ViewResources$HeadResponseWriter

/**
* License Agreement.
*
*  JBoss RichFaces - Ajax4jsf Component Library
*
* Copyright (C) 2007  Exadel, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* 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.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
*/

package org.ajax4jsf.context;

import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import javax.el.ExpressionFactory;
import javax.el.ValueExpression;
import javax.faces.FacesException;
import javax.faces.FactoryFinder;
import javax.faces.application.Application;
import javax.faces.component.UIComponent;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.RenderKit;
import javax.faces.render.RenderKitFactory;
import javax.faces.render.Renderer;

import org.ajax4jsf.component.QueueRegistry;
import org.ajax4jsf.io.SAXResponseWriter;
import org.ajax4jsf.renderkit.HeaderResourceProducer;
import org.ajax4jsf.renderkit.HeaderResourceProducer2;
import org.ajax4jsf.renderkit.ProducerContext;
import org.ajax4jsf.renderkit.ProducerContextImpl;
import org.ajax4jsf.renderkit.UserResourceRenderer;
import org.ajax4jsf.renderkit.UserResourceRenderer2;
import org.ajax4jsf.renderkit.RendererUtils.HTML;
import org.ajax4jsf.resource.InternetResource;
import org.ajax4jsf.resource.InternetResourceBase;
import org.ajax4jsf.resource.InternetResourceBuilder;
import org.ajax4jsf.resource.ResourceNotFoundException;
import org.ajax4jsf.resource.ResourceRenderer;
import org.ajax4jsf.resource.URIInternetResource;
import org.ajax4jsf.util.ELUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.richfaces.skin.Skin;
import org.richfaces.skin.SkinFactory;
import org.richfaces.skin.SkinNotFoundException;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

/**
* @author Nick Belaevski
*/

public class ViewResources {

  private static final String INIT_PARAMETER_PREFIX = "_init_parameter_";
  private static final Object NULL = new Object();

  private String scriptStrategy;

  private String styleStrategy;

  private boolean useStdControlsSkinning;

  private boolean useStdControlsSkinningClasses;

  private HeadResponseWriter componentWriter;

  private HeadResponseWriter userWriter;

  private RenderKit renderKit;

  private Node[] headNodes = null;

  private static final String EXTENDED_SKINNING_ON_NO_SCRIPTS_INFO_KEY = ViewResources.class.getName() + "EXTENDED_SKINNING_ON_NO_SCRIPTS_INFO_KEY";
 
  private static final InternetResource EXTENDED_SKINNING_ON_RESOURCE = new InternetResourceBase() {
   
    private final String RESOURCE_KEY = this.getClass().getName();
   
    @Override
    public void encode(FacesContext context, Object data)
        throws IOException {

      encode(context, data, Collections.EMPTY_MAP);
    }
   
    @Override
    public void encode(FacesContext context, Object data,
        Map<String, Object> attributes) throws IOException {

      Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
      if (requestMap.get(RESOURCE_KEY) == null) {
        ResponseWriter writer = context.getResponseWriter();
        writer.startElement(HTML.SCRIPT_ELEM, null);
       
        if (!attributes.containsKey(HTML.TYPE_ATTR)) {
          writer.writeAttribute(HTML.TYPE_ATTR, "text/javascript", null);
        }
       
        for (Map.Entry<String, Object> entry : attributes.entrySet()) {
          writer.writeAttribute(entry.getKey(), entry.getValue(), null);
        }
       
        writer.writeText("window.RICH_FACES_EXTENDED_SKINNING_ON=true;", null);
       
        writer.endElement(HTML.SCRIPT_ELEM);

        requestMap.put(RESOURCE_KEY, Boolean.TRUE);
      }
    }
  };
 
  public void setScriptStrategy(String scriptsStrategy) {
    this.scriptStrategy = scriptsStrategy;
  }

  public void setStyleStrategy(String stylesStrategy) {
    this.styleStrategy = stylesStrategy;
  }

  public void setUseStdControlsSkinning(boolean stdControlsSkinning) {
    this.useStdControlsSkinning = stdControlsSkinning;
  }

  public void setUseStdControlsSkinningClasses(boolean stdControlsSkinningClasses) {
    this.useStdControlsSkinningClasses = stdControlsSkinningClasses;
  }

  public void setExtendedSkinningAllowed(boolean extendedSkinningAllowed) {
    this.extendedSkinningAllowed = extendedSkinningAllowed;
  }

  private static String SCRIPT = HTML.SCRIPT_ELEM;
  private static String SCRIPT_UC = SCRIPT.toUpperCase(Locale.US);
 
  private static String SRC = HTML.src_ATTRIBUTE;
  private static String SRC_UC = SRC.toUpperCase(Locale.US);

  private void mergeHeadResourceNode(List<Node> nodes, Set<String> renderedScripts, Node node) {
    boolean shouldAdd = true;
   
    String nodeName = node.getNodeName();
    if (SCRIPT.equals(nodeName) || SCRIPT_UC.equals(nodeName)) {
      if (node.getFirstChild() == null) {
        //no text content etc.
     
        NamedNodeMap attributes = node.getAttributes();
        if (attributes != null) {
          Node item = attributes.getNamedItem(SRC);
          if (item == null) {
            attributes.getNamedItem(SRC_UC);
          }
         
          if (item != null) {
            String src = item.getNodeValue();
            if (src != null) {
              if (renderedScripts.contains(src)) {
                shouldAdd = false;
              } else {
                renderedScripts.add(src);
              }
            }
          }
        }
      }
    }
   
    if (shouldAdd) {
      nodes.add(node);
    }
  }
 
  private Node[] mergeHeadResourceNodes() {
    List<Node> result = new ArrayList<Node>();
 
    Set<String> scripts = new HashSet<String>();
   
    for (Node node : componentWriter.getNodes()) {
      mergeHeadResourceNode(result, scripts, node);
    }
   
    for (Node node : userWriter.getNodes()) {
      mergeHeadResourceNode(result, scripts, node);
    }
   
    return result.toArray(new Node[result.size()]);
  }
 
  public Node[] getHeadEvents() {
    if (headNodes == null) {
      headNodes = mergeHeadResourceNodes();
    }
   
    return headNodes;
  }

  private static final Log log = LogFactory.getLog(ViewResources.class);

  //todo

  private static final Map<String, Object> EXTENDED_SKINNING = new HashMap<String, Object>(1);

  static {
    EXTENDED_SKINNING.put(HTML.media_ATTRIBUTE, "rich-extended-skinning");
  }

  public static final String SKINNING_STYLES_PATH = "/org/richfaces/renderkit/html/css/";

  public static final String QUEUE_SCRIPT_RESOURCE = "org.ajax4jsf.renderkit.html.scripts.QueueScript";

  private boolean extendedSkinningAllowed;

  private boolean processScripts;

  private boolean processStyles;

  private boolean useSkinning;

  private InternetResourceBuilder resourceBuilder;

  private boolean ajaxRequest;

  private ProducerContext producerContext;

  public static final String COMPONENT_RESOURCE_LINK_CLASS = "component";

  public static final String USER_RESOURCE_LINK_CLASS = "user";

  class HeadResponseWriter extends SAXResponseWriter {

    public Node[] getNodes() {
      return ((ResponseWriterContentHandler) getXmlConsumer()).getNodes();
    }

    public HeadResponseWriter(String linkClass) {
      super(new ResponseWriterContentHandler(linkClass));

    }
  }

  private void encodeResources(FacesContext context, ResourceRenderer renderer, Set<String> set) throws IOException {

    if (set != null) {
      URIInternetResource resourceImpl = new URIInternetResource();

      for (String uri : set) {
        resourceImpl.setUri(uri);
        renderer.encode(resourceImpl, context, null);
      }
    }
  }

  private boolean encodeSkinningResources(FacesContext context, InternetResourceBuilder resourceBuilder) throws IOException, FacesException {
    String resourceSuffix = null;

    if (useStdControlsSkinning) {
      if (useStdControlsSkinningClasses) {
        resourceSuffix = "_both.xcss";
      } else {
        resourceSuffix = ".xcss";
      }
    } else {
      if (useStdControlsSkinningClasses) {
        resourceSuffix = "_classes.xcss";
      } else {
        //no resources
      }
    }

    if (resourceSuffix != null) {
      resourceBuilder.createResource(
          this, SKINNING_STYLES_PATH.concat("basic").concat(resourceSuffix)).encode(context, null);

      if (extendedSkinningAllowed) {
        resourceBuilder.createResource(
            this, SKINNING_STYLES_PATH.concat("extended").concat(resourceSuffix)).encode(context, null, EXTENDED_SKINNING);
      }

      return true;
    }

    return false;
  }

  protected void processComponent(FacesContext context, UIComponent component) throws IOException, FacesException {
    Renderer renderer = getRenderer(context, component);
    if (null != renderer) {
      ResponseWriter oldResponseWriter = context.getResponseWriter();
      try {
        if ((processScripts || processStyles)
            && (renderer instanceof HeaderResourceProducer2 || renderer instanceof HeaderResourceProducer)) {

          context.setResponseWriter(componentWriter);

          if (renderer instanceof HeaderResourceProducer2) {
            HeaderResourceProducer2 producer = (HeaderResourceProducer2) renderer;

            if (producerContext == null) {
              producerContext = new ProducerContextImpl(processScripts, processStyles);
            }

            producer.encodeToHead(context, component, producerContext);
          } else if (renderer instanceof HeaderResourceProducer) {
            HeaderResourceProducer producer = (HeaderResourceProducer) renderer;

            if (processScripts) {
              encodeResources(context, resourceBuilder.getScriptRenderer(), producer.getHeaderScripts(context,
                  component));
            }
            if (processStyles) {
              encodeResources(context, resourceBuilder.getStyleRenderer(), producer.getHeaderStyles(context,
                  component));
            }
          }
        } else if (renderer instanceof UserResourceRenderer2) {
          context.setResponseWriter(userWriter);

          UserResourceRenderer2 producer = (UserResourceRenderer2) renderer;
          producer.encodeToHead(context, component);
        } else if (renderer instanceof UserResourceRenderer) {
          context.setResponseWriter(userWriter);

          UserResourceRenderer producer = (UserResourceRenderer) renderer;

          encodeResources(context, resourceBuilder.getScriptRenderer(), producer.getHeaderScripts(context,
              component));

          encodeResources(context, resourceBuilder.getStyleRenderer(), producer.getHeaderStyles(context,
              component));
        }
      } finally {
        context.setResponseWriter(oldResponseWriter);
      }
    }

  }

  /**
   * Find renderer for given component.
   *
   * @param context
   * @param comp
   * @param renderKit
   * @return
   */
  private Renderer getRenderer(FacesContext context, UIComponent comp) {

    String rendererType = comp.getRendererType();
    if (rendererType != null) {
      return (renderKit.getRenderer(comp.getFamily(), rendererType));
    } else {
      return (null);
    }
  }

  protected void traverse(FacesContext context, UIComponent component) throws IOException, FacesException {
    if (component != null) {
      processComponent(context, component);

      if (component.getChildCount() > 0) {
        for (UIComponent child : component.getChildren()) {
          traverse(context, child);
        }
      }

      if (component.getFacetCount() > 0) {
        for (UIComponent child : component.getFacets().values()) {
          traverse(context, child);
        }
      }
    }
  }

  public void processHeadResources(FacesContext context) throws FacesException {

    RenderKitFactory rkFactory = (RenderKitFactory) FactoryFinder
    .getFactory(FactoryFinder.RENDER_KIT_FACTORY);
    renderKit = rkFactory.getRenderKit(context, context
        .getViewRoot().getRenderKitId());

    boolean scriptsOff = false;
   
    processStyles = true;
    processScripts = true;
    useSkinning = false;

    ajaxRequest = AjaxContext.getCurrentInstance(context).isAjaxRequest(context);

    if (log.isDebugEnabled()) {
      log
      .debug("Process component tree for collect used scripts and styles");
    }

    String skinStyleSheetUri = null;
    String skinExtendedStyleSheetUri = null;

    Skin skin = null;
    try {
      skin = SkinFactory.getInstance().getSkin(context);
      // For a "NULL" skin, do not collect components stylesheets
      if ("false".equals(skin.getParameter(context,
          Skin.loadStyleSheets))) {
        processStyles = false;
      }
      // Set default style sheet for current skin.
      skinStyleSheetUri = (String) skin.getParameter(context,
          Skin.generalStyleSheet);
      // Set default style sheet for current skin.
      skinExtendedStyleSheetUri = (String) skin.getParameter(context,
          Skin.extendedStyleSheet);
    } catch (SkinNotFoundException e) {
      if (log.isWarnEnabled()) {
        log.warn("Current Skin is not found", e);
      }
    }

    resourceBuilder = InternetResourceBuilder.getInstance();

    ResponseWriter oldResponseWriter = context.getResponseWriter();

    componentWriter = new HeadResponseWriter("component");
    userWriter = new HeadResponseWriter("user");

    try {
      componentWriter.startDocument();
      userWriter.startDocument();

      context.setResponseWriter(componentWriter);

      // Check init parameters for a resources processing.
      if (null != scriptStrategy) {
        if (InternetResourceBuilder.LOAD_NONE
            .equals(scriptStrategy)) {
          scriptsOff = true;
          processScripts = false;
        } else if (InternetResourceBuilder.LOAD_ALL
            .equals(scriptStrategy)) {
          processScripts = false;
          // For an "ALL" strategy, it is not necessary to load scripts in the ajax request
          if (!ajaxRequest) {
            try {
              resourceBuilder
              .createResource(
                  this,
                  InternetResourceBuilder.COMMON_FRAMEWORK_SCRIPT).encode(context, null);
              resourceBuilder
              .createResource(
                  this,
                  InternetResourceBuilder.COMMON_UI_SCRIPT).encode(context, null);

            } catch (ResourceNotFoundException e) {
              if (log.isWarnEnabled()) {
                log
                .warn("No aggregated javaScript library found "
                    + e.getMessage());
              }
            }

          }
        }
      }

      if (InternetResourceBuilder.LOAD_NONE.equals(styleStrategy)) {
        processStyles = false;
      } else if (InternetResourceBuilder.LOAD_ALL
          .equals(styleStrategy)) {
        processStyles = false;
        // For an "ALL" strategy, it is not necessary to load styles
        // in the ajax request
        if (!ajaxRequest) {

          try {
            useSkinning = encodeSkinningResources(context, resourceBuilder);

            resourceBuilder
            .createResource(this, InternetResourceBuilder.COMMON_STYLE).encode(context, null);

          } catch (ResourceNotFoundException e) {
            if (log.isWarnEnabled()) {
              log.warn("No stylesheet found "
                  + e.getMessage());
            }
          }

        }
      } else {
        useSkinning = encodeSkinningResources(context, resourceBuilder);
      }

      //traverse components
      traverse(context, context.getViewRoot());

      context.setResponseWriter(componentWriter);

      QueueRegistry queueRegistry = QueueRegistry.getInstance(context);
      if (Boolean.valueOf(getInitParameterValue(context, "org.richfaces.queue.global.enabled"))) {
        queueRegistry.setShouldCreateDefaultGlobalQueue();
      }
     
      if (queueRegistry.hasQueuesToEncode()) {
        InternetResource queueScriptResource = resourceBuilder.getResource(QUEUE_SCRIPT_RESOURCE);
        queueScriptResource.encode(context, null);
      }
     
      // Append Skin StyleSheet after a
      if (null != skinStyleSheetUri) {
        String resourceURL = context.getApplication()
        .getViewHandler().getResourceURL(context,
            skinStyleSheetUri);

        URIInternetResource resourceImpl = new URIInternetResource();
        resourceImpl.setUri(resourceURL);
        resourceImpl.setRenderer(resourceBuilder.getStyleRenderer());
        resourceImpl.encode(context, null);

        useSkinning = true;
      }

      if (null != skinExtendedStyleSheetUri && extendedSkinningAllowed) {
        String resourceURL = context.getApplication().getViewHandler().getResourceURL(context,
            skinExtendedStyleSheetUri);

        URIInternetResource resourceImpl = new URIInternetResource();
        resourceImpl.setUri(resourceURL);
        resourceImpl.setRenderer(resourceBuilder.getStyleRenderer());
        resourceImpl.encode(context, null, EXTENDED_SKINNING);

        useSkinning = true;
      }

      if (useSkinning && extendedSkinningAllowed) {
        if (!ajaxRequest) {
          if (!scriptsOff) {
            //skinning levels aren't dynamic, page-level setting cannot be changed
            //by AJAX request
            EXTENDED_SKINNING_ON_RESOURCE.encode(context, null);
          } else {
           
            Map<String, Object> applicationMap = context.getExternalContext().getApplicationMap();
            if (applicationMap.get(EXTENDED_SKINNING_ON_NO_SCRIPTS_INFO_KEY) == null) {
              //do it once per application life - strategies can be changed dynamically
              ResponseWriter writer = context.getResponseWriter();
              try {
                StringWriter stringWriter = new StringWriter();
               
                if (oldResponseWriter != null) {
                  context.setResponseWriter(oldResponseWriter.cloneWithWriter(stringWriter));
                } else {
                  context.setResponseWriter(this.renderKit.createResponseWriter(
                      stringWriter, "text/html",
                      "US-ASCII"));
                }
               
               
                EXTENDED_SKINNING_ON_RESOURCE.encode(context, null);

                stringWriter.flush();
               
                if (log.isInfoEnabled()) {
                  log.info("Extended skinning is on and NONE scripts loading strategy was detected. " +
                      "Do not forget that one of " + InternetResourceBuilder.SKINNING_SCRIPT + " or " +
                      InternetResourceBuilder.COMMON_FRAMEWORK_SCRIPT + " resources should be presented " +
                      "on the page together with the following code: \n" + stringWriter.getBuffer().toString() +
                      "\nfor extended level of skinning to work.");
                }
              } finally {
                if (writer != null) {
                  context.setResponseWriter(writer);
                }
              }

              applicationMap.put(EXTENDED_SKINNING_ON_NO_SCRIPTS_INFO_KEY, Boolean.TRUE);
            }
          }
        }

        if (processScripts) {
          InternetResource resource = resourceBuilder.createResource(null,
            InternetResourceBuilder.SKINNING_SCRIPT);

          resource.encode(context, null);
        }
      }

      componentWriter.endDocument();
      userWriter.endDocument();
    } catch (IOException e) {
      throw new FacesException(e.getLocalizedMessage(), e);
    } finally {
      if (oldResponseWriter != null) {
        context.setResponseWriter(oldResponseWriter);
      }
    }
  }

  private static String getInitParameterValue(FacesContext context, String parameterName) {
   
    String key = INIT_PARAMETER_PREFIX + parameterName;
   
    ExternalContext externalContext = context.getExternalContext();
    Map<String, Object> applicationMap = externalContext.getApplicationMap();
    Object mutex = externalContext.getRequest();
    Object parameterValue = null;
   
    synchronized (mutex) {
      parameterValue = applicationMap.get(key);

      if (parameterValue == null) {

        String initParameter = externalContext.getInitParameter(parameterName);
        if (initParameter != null) {
         
          if (ELUtils.isValueReference(initParameter)) {
            Application application = context.getApplication();
            ExpressionFactory expressionFactory = application.getExpressionFactory();
           
            parameterValue = expressionFactory.createValueExpression(context.getELContext(),
                initParameter,
                String.class);
          } else {
            parameterValue = initParameter;
          }
         
        } else {
          parameterValue = NULL;
        }
       
        applicationMap.put(key, parameterValue);
      }
    }
   
    return evaluate(context, parameterValue);
  }
 
  private static String evaluate(FacesContext context, Object parameterValue) {
    if (parameterValue == NULL || parameterValue == null) {
      return null;
    } else if (parameterValue instanceof ValueExpression) {
      ValueExpression expression = (ValueExpression) parameterValue;
     
      return (String) expression.getValue(context.getELContext());
    } else {
      return parameterValue.toString();
    }
  }

  public void initialize(FacesContext context) {
    boolean extendedSkinningAllowed = true;
    String skinningLevel = getInitParameterValue(context, InternetResourceBuilder.CONTROL_SKINNING_LEVEL);
    if (skinningLevel != null && skinningLevel.length() > 0) {
      if (InternetResourceBuilder.BASIC.equals(skinningLevel)) {
        extendedSkinningAllowed = false;
      } else if (!InternetResourceBuilder.EXTENDED.equals(skinningLevel)) {
        throw new IllegalArgumentException("Value: " + skinningLevel +
            " of " + InternetResourceBuilder.CONTROL_SKINNING_LEVEL
            + " init parameter is invalid! Only " + InternetResourceBuilder.EXTENDED
            + ", " + InternetResourceBuilder.BASIC + " can be used");
      }
    }
   
    this.setExtendedSkinningAllowed(extendedSkinningAllowed);
   
    this.setScriptStrategy(getInitParameterValue(context,
        InternetResourceBuilder.LOAD_SCRIPT_STRATEGY_PARAM));

    boolean useStdControlsSkinning = false;

    String stdControlsSkinning = getInitParameterValue(context, InternetResourceBuilder.STD_CONTROLS_SKINNING_PARAM);
    if (stdControlsSkinning != null) {
      useStdControlsSkinning = InternetResourceBuilder.ENABLE.equals(stdControlsSkinning);
    }
   
    this.setUseStdControlsSkinning(useStdControlsSkinning);

    boolean useStdControlsSkinningClasses = true;

    String stdControlsSkinningClasses = getInitParameterValue(context, InternetResourceBuilder.STD_CONTROLS_SKINNING_CLASSES_PARAM);
    if (stdControlsSkinningClasses != null) {
      useStdControlsSkinningClasses = InternetResourceBuilder.ENABLE.equals(stdControlsSkinningClasses);
    }

    this.setUseStdControlsSkinningClasses(useStdControlsSkinningClasses);
   
    this.setStyleStrategy(getInitParameterValue(context,
        InternetResourceBuilder.LOAD_STYLE_STRATEGY_PARAM));


  }
 
}
TOP

Related Classes of org.ajax4jsf.context.ViewResources$HeadResponseWriter

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.