Package org.ajax4jsf.context

Source Code of org.ajax4jsf.context.AjaxContextImpl

/**
* License Agreement.
*
* Rich Faces - Natural Ajax for Java Server Faces (JSF)
*
* 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.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;

import javax.faces.FacesException;
import javax.faces.application.Application;
import javax.faces.application.StateManager;
import javax.faces.application.ViewHandler;
import javax.faces.application.StateManager.SerializedView;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.event.AbortProcessingException;
import javax.faces.render.RenderKit;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.ajax4jsf.Messages;
import org.ajax4jsf.application.AjaxViewHandler;
import org.ajax4jsf.component.AjaxContainer;
import org.ajax4jsf.component.AjaxViewRoot;
import org.ajax4jsf.renderkit.AjaxContainerRenderer;
import org.ajax4jsf.renderkit.AjaxRendererUtils;
import org.ajax4jsf.renderkit.RendererUtils;
import org.ajax4jsf.renderkit.UserResourceRenderer;
import org.ajax4jsf.renderkit.RendererUtils.HTML;
import org.ajax4jsf.resource.InternetResourceBuilder;
import org.ajax4jsf.webapp.BaseFilter;
import org.ajax4jsf.webapp.FilterServletResponseWrapper;
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;

/**
* This class incapsulated
*
* @author asmirnov@exadel.com (latest modification by $Author: alexsmirnov $)
* @version $Revision: 1.1.2.7 $ $Date: 2007/02/08 19:07:16 $
*
*/
public class AjaxContextImpl extends AjaxContext {
  public static final String RESOURCES_PROCESSED = "org.ajax4jsf.framework.HEADER_PROCESSED";

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

  private static ComponentInvoker invoker;

  private static Map contextClasses = new HashMap();

  Set ajaxAreasToRender = new HashSet();

  Set ajaxRenderedAreas = new LinkedHashSet();

  boolean ajaxRequest = false;

  boolean ajaxRequestSet = false;

  boolean selfRender = false;

  Integer viewSequence = new Integer(1);

  String submittedRegionClientId = null;

  boolean submittedRegionSet = false;

  ViewIdHolder viewIdHolder = null;

  Map responseDataMap = new HashMap();

  Map commonAjaxParameters = new HashMap();
 
  Object oncomplete = null;

  static {
    try {
      // Attempt to create JSF1.2 specific invoker.
      invoker = new JsfOneOneInvoker();
    } catch (Exception e) {
      invoker = new JsfOneOneInvoker();
    }
  }
 
  public void release() {
   
    ajaxAreasToRender = new HashSet();

    ajaxRenderedAreas = new LinkedHashSet();

    ajaxRequest = false;

    ajaxRequestSet = false;

    selfRender = false;

    viewSequence = new Integer(1);

    submittedRegionClientId = null;

    submittedRegionSet = false;

    viewIdHolder = null;

    responseDataMap = new HashMap();

    commonAjaxParameters = new HashMap();
   
  }

  /**
   * @param root
   * @param context
   * @param callback
   * @param regionId
   * @return
   * @see org.ajax4jsf.context.JsfOneOneInvoker#invokeOnComponent(javax.faces.component.UIComponent,
   *      javax.faces.context.FacesContext,
   *      org.ajax4jsf.context.InvokerCallback, java.lang.String)
   */
  public static boolean invokeOnComponent(UIComponent root,
      FacesContext context, InvokerCallback callback, String regionId) {
    return invoker.invokeOnComponent(root, context, callback, regionId);
  }

  /**
   * @param viewRoot
   * @param context
   * @param callback
   * @see org.ajax4jsf.context.JsfOneOneInvoker#invokeOnRegionOrRoot(org.ajax4jsf.component.AjaxViewRoot,
   *      javax.faces.context.FacesContext,
   *      org.ajax4jsf.context.InvokerCallback)
   */
  public static void invokeOnRegionOrRoot(AjaxViewRoot viewRoot,
      FacesContext context, InvokerCallback callback) {
    invoker.invokeOnRegionOrRoot(viewRoot, context, callback);
  }

  private InvokerCallback _ajaxInvoker = new InvokerCallback() {

    public void invoke(FacesContext context, UIComponent component) {
      if (component instanceof AjaxContainer) {
        AjaxContainer ajax = (AjaxContainer) component;
        renderAjaxRegion(context, component, true);
      } else {
        // Container not found, use Root for encode.
        renderAjaxRegion(context, context.getViewRoot(), true);
      }
    }

    public void invokeRoot(FacesContext context) {
      renderAjaxRegion(context, context.getViewRoot(), true);
    }

  };

  public void renderSubmittedAjaxRegion(FacesContext context) {
    renderSubmittedAjaxRegion(context, true);
  }

  public void renderSubmittedAjaxRegion(FacesContext context,
      final boolean useFilterWriter) {
    InvokerCallback ajaxInvoker = new InvokerCallback() {

      public void invoke(FacesContext context, UIComponent component) {
        if (component instanceof AjaxContainer) {
          renderAjaxRegion(context, component, useFilterWriter);
        } else {
          // Container not found, use Root for encode.
          renderAjaxRegion(context, context.getViewRoot(),
              useFilterWriter);
        }
      }

      public void invokeRoot(FacesContext context) {
        renderAjaxRegion(context, context.getViewRoot(),
            useFilterWriter);
      }

    };
    if (!invokeOnComponent(context.getViewRoot(), context, ajaxInvoker,
        getSubmittedRegionClientId(context))) {
      renderAjaxRegion(context, context.getViewRoot(), useFilterWriter);
    }

  }

  /**
   * @param context
   * @param useFilterWriter
   *            TODO
   * @throws AbortProcessingException
   */
  public void renderAjaxRegion(FacesContext context, UIComponent component,
      boolean useFilterWriter) throws FacesException {
    if (log.isDebugEnabled()) {
      log.debug(Messages.getMessage(Messages.RENDER_AJAX_REQUEST,
          component.getId()));
    }
    try {
      setSelfRender(true);
      // create response writer.
      ExternalContext extContext = context.getExternalContext();
      RenderKit renderKit = context.getRenderKit();
      String encoding;
      // Depends if we talk about servlets, portlets, ...
      if (extContext.getRequest() instanceof ServletRequest) {
        ServletRequest request = (ServletRequest) extContext
            .getRequest();
        ServletResponse response = (ServletResponse) extContext
            .getResponse();
        // HACK - bypass MyFaces ( and other ) extensions filter.

        // Setup encoding and content type
        String contentType = "text/xml";
        // get the encoding - must be setup by faces context or filter.
        encoding = request.getCharacterEncoding();
        if (encoding == null) {
          encoding = "UTF-8";
        }
        response.setContentType(contentType + ";charset=" + encoding);
      } else
        encoding = "UTF-8";

      PrintWriter servletWriter;
      if (useFilterWriter
          && extContext.getRequestMap().containsKey(
              BaseFilter.RESPONSE_WRAPPER_ATTRIBUTE)) {
        // HACK - Special case for MyFaces, since <f:view don't call
        // encode methods,
        // encode response as for self-rendered region directly to
        // filter response wrpper.
        // to avoid exceptions, inform wrapper to ignore illegal states
        // for getWriter/Stream.
        ServletResponse servletResponse = (ServletResponse) extContext
            .getRequestMap().get(
                BaseFilter.RESPONSE_WRAPPER_ATTRIBUTE);
        servletResponse.resetBuffer();
        servletWriter = servletResponse.getWriter();
        ((FilterServletResponseWrapper) servletResponse)
            .setUseNullStream(true);
      } else {
        servletWriter = getWriter(extContext);
      }
      ResponseWriter writer = renderKit.createResponseWriter(
          servletWriter, null, encoding);
      context.setResponseWriter(writer);
      // make response
      writer.startDocument();
      encodeAjaxBegin(context, component);
      component.encodeBegin(context);
      ((AjaxContainer) component).encodeAjax(context);
      component.encodeEnd(context);
      saveViewState(context);
      encodeAjaxEnd(context, component);
      writer.endDocument();
      writer.flush();
      writer.close();
      servletWriter.close();
      // Save tree state.
    } catch (IOException e) {
      throw new FacesException(Messages.getMessage(
          Messages.RENDERING_AJAX_REGION_ERROR, component
              .getClientId(context)), e);
    } finally {
      context.responseComplete();
      // component.setRendererType(defaultRenderer);
    }
  }

  /**
   * Encode declaration for AJAX response. Render &lt;html&gt;&lt;body&gt;
   *
   * @param context
   * @param component
   * @throws IOException
   */
  public void encodeAjaxBegin(FacesContext context, UIComponent component)
      throws IOException {
    // AjaxContainer ajax = (AjaxContainer) component;
    ResponseWriter out = context.getResponseWriter();
    // DebugUtils.traceView("ViewRoot in AJAX Page encode begin");
    out.startElement(HTML.HTML_ELEMENT, component);
    // TODO - html attributes. lang - from current locale ?
    Locale locale = context.getViewRoot().getLocale();
    out.writeAttribute(HTML.lang_ATTRIBUTE, locale.toString(), "lang");
    out.startElement(HTML.BODY_ELEMENT, component);
  }

  /**
   * End encoding of AJAX response. Render tag with included areas and close
   * &lt;/body&gt;&lt;/html&gt;
   *
   * @param context
   * @param component
   * @throws IOException
   */
  public void encodeAjaxEnd(FacesContext context, UIComponent component)
      throws IOException {
    // AjaxContainer ajax = (AjaxContainer) component;
    ResponseWriter out = context.getResponseWriter();
    // DebugUtils.traceView("ViewRoot in AJAX Page encode begin");
    out.endElement(HTML.BODY_ELEMENT);
    out.endElement(HTML.HTML_ELEMENT);
  }

  /**
   * @param context
   * @param root
   * @throws FacesException
   */
  public void processHeadResources(FacesContext context)
      throws FacesException {
    ExternalContext externalContext = context.getExternalContext();
    Map requestMap = externalContext.getRequestMap();
    if (!Boolean.TRUE.equals(requestMap.get(RESOURCES_PROCESSED))) {
      if (null != requestMap.get(BaseFilter.RESPONSE_WRAPPER_ATTRIBUTE)) {
        if (log.isDebugEnabled()) {
          log
              .debug("Process component tree for collect used scripts and styles");
        }
        UIViewRoot root = context.getViewRoot();
        ViewResources viewResources = new ViewResources();
        try {
          Skin skin = SkinFactory.getInstance().getSkin(
              context);
          // Set default style sheet for current skin.
          String styleSheetUri = (String) skin.getParameter(context,
              Skin.generalStyleSheet);
          if(null != styleSheetUri){
            String resourceURL = context.getApplication()
            .getViewHandler().getResourceURL(context,
                styleSheetUri);
            viewResources.addStyle(resourceURL);
          }
          // For a "NULL" skin, do not collect components stylesheets
          if("false".equals(skin.getParameter(context, Skin.loadStyleSheets))){
            viewResources.setProcessStyles(false);
          }
        } catch (SkinNotFoundException e) {
          log.warn("Current Skin is not found", e);
        }
        InternetResourceBuilder internetResourceBuilder = InternetResourceBuilder.getInstance();
        // Check init parameters for a resources processing.
        String scriptStrategy = externalContext.getInitParameter(InternetResourceBuilder.LOAD_SCRIPT_STRATEGY_PARAM);
        if(null != scriptStrategy){
          if(InternetResourceBuilder.LOAD_NONE.equals(scriptStrategy)){
            viewResources.setProcessScripts(false);
          } else if (InternetResourceBuilder.LOAD_ALL.equals(scriptStrategy)) {
            viewResources.setProcessScripts(false);
            viewResources.addScript(internetResourceBuilder.createResource(this, InternetResourceBuilder.COMMON_FRAMEWORK_SCRIPT).getUri(context, null));
            viewResources.addScript(internetResourceBuilder.createResource(this, InternetResourceBuilder.COMMON_UI_SCRIPT).getUri(context, null));
          }
        }
        String styleStrategy = externalContext.getInitParameter(InternetResourceBuilder.LOAD_STYLE_STRATEGY_PARAM);
        if(null != styleStrategy){
          if(InternetResourceBuilder.LOAD_NONE.equals(styleStrategy)){
            viewResources.setProcessStyles(false);
          } else if (InternetResourceBuilder.LOAD_ALL.equals(styleStrategy)) {
            viewResources.setProcessStyles(false);
            viewResources.addStyle(internetResourceBuilder.createResource(this, InternetResourceBuilder.COMMON_STYLE).getUri(context, null));
          }
        }
        viewResources.collect(context);
        Set scripts = viewResources.getScripts();
        if (scripts.size() > 0) {
          if (log.isDebugEnabled()) {
            StringBuffer buff = new StringBuffer(
                "Scripts for insert into head : \n");
            for (Iterator iter = scripts.iterator(); iter.hasNext();) {
              String script = (String) iter.next();
              buff.append(script).append("\n");
            }
            log.debug(buff.toString());
          }
          requestMap.put(SCRIPTS_PARAMETER, scripts);
        }
        Set styles = viewResources.getStyles();
        if (styles.size() > 0) {
          if (log.isDebugEnabled()) {
            StringBuffer buff = new StringBuffer(
                "Styles for insert into head : \n");
            for (Iterator iter = styles.iterator(); iter.hasNext();) {
              String style = (String) iter.next();
              buff.append(style).append("\n");
            }
            log.debug(buff.toString());
          }
          requestMap.put(STYLES_PARAMETER, styles);
        }
        // Mark as processed.
        requestMap.put(RESOURCES_PROCESSED, Boolean.TRUE);
        // Save viewId for a parser selection
        requestMap.put(AjaxViewHandler.VIEW_ID_KEY, root.getViewId());
      }

    }
  }

  public void saveViewState(FacesContext context) throws IOException {
    // TODO - for facelets environment, we need to remove transient
    // components.
    try {
      Application.class.getMethod("getExpressionFactory", null);
    } catch (NoSuchMethodException e) {
      // JSF 1.1 !
    }
    ResponseWriter writer = context.getResponseWriter();
    StateManager stateManager = context.getApplication().getStateManager();
    SerializedView serializedView = stateManager
        .saveSerializedView(context);
    if (null != writer && null != serializedView) {
      StringWriter bufWriter = new StringWriter();
      ResponseWriter cloneWithWriter = writer.cloneWithWriter(bufWriter);
      context.setResponseWriter(cloneWithWriter);
      stateManager.writeState(context, serializedView);
      cloneWithWriter.flush();
      if (bufWriter.getBuffer().length() > 0) {
        context.getExternalContext().getRequestMap().put(
            AjaxViewHandler.SERIALIZED_STATE_KEY,
            bufWriter.toString());
      }
      // Restore original writer.
      context.setResponseWriter(writer);
    }
  }

  /**
   * @return Returns the ajaxRequest.
   */
  public boolean isAjaxRequest() {
    return isAjaxRequest(FacesContext.getCurrentInstance());
  }

  /**
   * @return Returns the ajaxRequest.
   */
  public boolean isAjaxRequest(FacesContext context) {
    if (!this.ajaxRequestSet) {
      ajaxRequest = null != getSubmittedRegionClientId(context);
      ajaxRequestSet = true;
    }
    return ajaxRequest;
  }

  /**
   * @param ajaxRequest
   *            The ajaxRequest to set.
   */
  public void setAjaxRequest(boolean ajaxRequest) {
    this.ajaxRequest = ajaxRequest;
    this.ajaxRequestSet = true;
  }

  /**
   * @return Returns the ajaxAreasToRender.
   */
  public Set getAjaxAreasToRender() {
    return this.ajaxAreasToRender;
  }

  /**
   * Add affected regions's ID to ajaxView component.
   *
   * @param component
   */
  public void addRegionsFromComponent(UIComponent component) {
    // First step - find parent ajax view
    Set ajaxRegions = AjaxRendererUtils.getAjaxAreas(component);
    // if (ajaxRegions == null){
    // FacesContext context = FacesContext.getCurrentInstance();
    // ajaxRegions = AjaxRendererUtils.getAbsoluteId(context,component);
    // }
    if (log.isDebugEnabled()) {
      log.debug(Messages.getMessage(Messages.INVOKE_AJAX_REGION_LISTENER,
          component.getId()));
    }
    if (ajaxRegions != null) {
      for (Iterator iter = ajaxRegions.iterator(); iter.hasNext();) {
        String id = iter.next().toString();
        ajaxAreasToRender.add(convertId(component, id));
      }
    }
  }

  public void addComponentToAjaxRender(UIComponent component) {
    this.ajaxAreasToRender.add(AjaxRendererUtils.getAbsoluteId(component));
  }

  public void addComponentToAjaxRender(UIComponent base, String id) {
    this.ajaxAreasToRender.add(convertId(base, id));
  }

  /**
   * Test for relative id of target components. Attempt convert to absolute.
   * For use as argument for
   * {@link RendererUtils#findComponentFor(UIComponent, String)}
   *
   * @param component
   * @param id
   * @return
   */
  private String convertId(UIComponent component, String id) {
    if (id.charAt(0) == NamingContainer.SEPARATOR_CHAR) {
      return id;
    }
    if (null == component) {
      throw new NullPointerException(
          "Base component for search re-rendered compnnent is null");
    }
    UIComponent target = RendererUtils.getInstance().
      findComponentFor(component, id);
    if (null != target) {
      return AjaxRendererUtils.getAbsoluteId(target);
    }
    log.warn("Target component for id " + id + " not found");
    return id;
  }

  /**
   * @return Returns the ajaxRenderedAreas.
   */
  public Set getAjaxRenderedAreas() {
    return ajaxRenderedAreas;
  }

  public void addRenderedArea(String id) {
    ajaxRenderedAreas.add(id);
  }

  public boolean removeRenderedArea(String id) {
    return ajaxRenderedAreas.remove(id);
  }

  /**
   * @return Returns the submittedClientId.
   */
  public String getSubmittedRegionClientId(FacesContext context) {
    if (!this.submittedRegionSet) {
      ExternalContext externalContext = context.getExternalContext();
      if (null == externalContext.getRequestMap().get(
          "javax.servlet.error.exception")) {
        Map requestParameterMap = externalContext
            .getRequestParameterMap();
        this.submittedRegionClientId = (String) requestParameterMap
            .get(AjaxContainerRenderer.AJAX_PARAMETER_NAME);

      } else {
        // Error page, always parsed as non-ajax request.
        this.submittedRegionClientId = null;
      }
      this.submittedRegionSet = true;
      if (!this.ajaxRequestSet) {
        setAjaxRequest(this.submittedRegionClientId != null);
      }
    }
    return this.submittedRegionClientId;
  }

  /**
   * @param submittedClientId
   *            The submittedClientId to set.
   */
  public void setSubmittedRegionClientId(String submittedClientId) {
    this.submittedRegionClientId = submittedClientId;
    this.submittedRegionSet = true;
  }

  /**
   * @return Returns the selfRender.
   */
  public boolean isSelfRender() {
    return selfRender;
  }

  /**
   * @param selfRender
   *            The selfRender to set.
   */
  public void setSelfRender(boolean selfRender) {
    this.selfRender = selfRender;
  }

  /**
   * @return the vievIdHolder
   */
  public ViewIdHolder getViewIdHolder() {
    return viewIdHolder;
  }

  /**
   * @param viewIdHolder
   *            the vievIdHolder to set
   */
  public void setViewIdHolder(ViewIdHolder viewIdHolder) {
    this.viewIdHolder = viewIdHolder;
  }

  /**
   * @return the responseData
   */
  public Object getResponseData() {
    return responseDataMap.get(RESPONSE_DATA_KEY);
  }

  /**
   * @param responseData
   *            the responseData to set
   */
  public void setResponseData(Object responseData) {
    this.responseDataMap.put(RESPONSE_DATA_KEY, responseData);
  }

  /**
   * @return the responseDataMap
   */
  public Map getResponseDataMap() {
    return responseDataMap;
  }

  /**
   * Gives back the writer of a Response object.
   *
   * @param extContext
   *            The external context.
   * @return The writer of the response.
   * @throws FacesException
   *             If the response object has no getWriter() method.
   */
  protected PrintWriter getWriter(ExternalContext extContext)
      throws FacesException {
    PrintWriter writer = null;
    Object response = extContext.getResponse();
    try {
      Method gW = response.getClass()
          .getMethod("getWriter", new Class[0]);
      writer = (PrintWriter) gW.invoke(response, new Object[0]);
    } catch (Exception e) {
      throw new FacesException(e);
    }
    return writer;
  }

  public String getAjaxActionURL() {
    return getAjaxActionURL(FacesContext.getCurrentInstance());
  }

  public String getAjaxActionURL(FacesContext context) {
    // Check arguments
    if (null == context) {
      throw new NullPointerException(
          "Faces context for build AJAX Action URL is null");
    }
    UIViewRoot viewRoot = context.getViewRoot();
    if (null == viewRoot) {
      throw new NullPointerException(
          "Faces view tree for build AJAX Action URL is null");
    }
    String viewId = viewRoot.getViewId();
    if (null == viewId) {
      throw new NullPointerException(
          "View id for build AJAX Action URL is null");
    }
    if (!viewId.startsWith("/")) {
      throw new IllegalArgumentException(
          "Illegal view Id for build AJAX Action URL: " + viewId);
    }
    ViewHandler viewHandler = context.getApplication().getViewHandler();
    String actionURL = viewHandler.getActionURL(context, viewId);
    // Mark Ajax action url as transparent with jsf-portlet bridge.
    actionURL = actionURL + ((actionURL.lastIndexOf('?')>0)?"&":"?")+"javax.portlet.faces.DirectLink=true";
    return context.getExternalContext().encodeActionURL(
        actionURL);
  }

  /**
   * @return the commonAjaxParameters
   */
  public Map getCommonAjaxParameters() {
    return commonAjaxParameters;
  }

  /**
   * @return the oncomplete
   */
  public Object getOncomplete() {
    return oncomplete;
  }

  /**
   * @param oncomplete the oncomplete to set
   */
  public void setOncomplete(Object oncomplete) {
    this.oncomplete = oncomplete;
  }

}
TOP

Related Classes of org.ajax4jsf.context.AjaxContextImpl

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.