Package org.apache.myfaces.context.servlet

Source Code of org.apache.myfaces.context.servlet.PartialViewContextImpl$PhaseAwareVisitCallback

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.myfaces.context.servlet;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.faces.FactoryFinder;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewParameter;
import javax.faces.component.UIViewRoot;
import javax.faces.component.visit.VisitCallback;
import javax.faces.component.visit.VisitContext;
import javax.faces.component.visit.VisitHint;
import javax.faces.component.visit.VisitResult;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.PartialResponseWriter;
import javax.faces.context.PartialViewContext;
import javax.faces.context.ResponseWriter;
import javax.faces.event.PhaseId;
import javax.faces.render.RenderKit;
import javax.faces.render.RenderKitFactory;
import javax.faces.view.ViewMetadata;

import org.apache.myfaces.context.PartialResponseWriterImpl;
import org.apache.myfaces.shared.util.StringUtils;

public class PartialViewContextImpl extends PartialViewContext {

    private static final String FACES_REQUEST = "Faces-Request";
    private static final String PARTIAL_AJAX = "partial/ajax";
    private static final String PARTIAL_PROCESS = "partial/process";
    private static final String SOURCE_PARAM_NAME = "javax.faces.source";
    /**
     * Internal extension for
     * https://issues.apache.org/jira/browse/MYFACES-2841
     * will be changed for 2.1 to the official marker
     */
    private static final String PARTIAL_IFRAME = "org.apache.myfaces.partial.iframe";

    private FacesContext _facesContext = null;
    private boolean _released = false;
    // Cached values, since their parent methods could be called
    // many times and the result does not change during the life time
    // of this object.
    private Boolean _ajaxRequest = null;

    /**
     * Internal extension for
     * https://issues.apache.org/jira/browse/MYFACES-2841
     * will be changed for 2.1 to the official marker
     */
    private Boolean _iframeRequest = null;

    private Collection<String> _executeClientIds = null;
    private Collection<String> _renderClientIds = null;
    // Values that need to be saved because exists a setXX method
    private Boolean _partialRequest = null;
    private Boolean _renderAll = null;
    private PartialResponseWriter _partialResponseWriter = null;

    public PartialViewContextImpl(FacesContext context) {
        _facesContext = context;
    }

    @Override
    public boolean isAjaxRequest() {
        assertNotReleased();
        /*
         * Internal extension for
         * https://issues.apache.org/jira/browse/MYFACES-2841
         * will be changed for 2.1 to the official marker
         */
        if (_iframeRequest == null) {
            isIFrameRequest();
        }
        if (_ajaxRequest == null) {
            String requestType = _facesContext.getExternalContext().
                    getRequestHeaderMap().get(FACES_REQUEST);
            _ajaxRequest = (requestType != null && PARTIAL_AJAX.equals(requestType));
        }
        //for now we have to treat the partial iframe request also as ajax request
        return _ajaxRequest || _iframeRequest;
    }

    @Override
    public boolean isExecuteAll() {
        assertNotReleased();

        if (isAjaxRequest()) {
            String executeMode = _facesContext.getExternalContext().
                    getRequestParameterMap().get(
                    PartialViewContext.PARTIAL_EXECUTE_PARAM_NAME);
            if (PartialViewContext.ALL_PARTIAL_PHASE_CLIENT_IDS.equals(executeMode)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean isPartialRequest() {
        assertNotReleased();

        if (_partialRequest == null) {
            String requestType = _facesContext.getExternalContext().
                    getRequestHeaderMap().get(FACES_REQUEST);
            _partialRequest = (requestType != null && PARTIAL_PROCESS.equals(requestType));
        }
        return isAjaxRequest()  || _partialRequest;
    }

    @Override
    public boolean isRenderAll() {
        assertNotReleased();

        if (_renderAll == null) {
            if (isAjaxRequest()) {
                String executeMode = _facesContext.getExternalContext().
                        getRequestParameterMap().get(
                        PartialViewContext.PARTIAL_RENDER_PARAM_NAME);
                if (PartialViewContext.ALL_PARTIAL_PHASE_CLIENT_IDS.equals(executeMode)) {
                    _renderAll = true;
                }
            }
            if (_renderAll == null) {
                _renderAll = false;
            }
        }
        return _renderAll;
    }

    /**
     * Extension for
     * https://issues.apache.org/jira/browse/MYFACES-2841
     * internal extension which detects that the submit is an iframe request
     * will be changed for the official version which will come in 2.1
     *
     * @return true if the current request is an iframe based ajax request
     */
    public boolean isIFrameRequest() {
        if(_iframeRequest == null) {
            _iframeRequest = _facesContext.getExternalContext().getRequestParameterMap().containsKey(PARTIAL_IFRAME);
        }
        return _iframeRequest;
    }

    @Override
    public void setPartialRequest(boolean isPartialRequest) {
        assertNotReleased();

        _partialRequest = isPartialRequest;

    }

    @Override
    public void setRenderAll(boolean renderAll) {
        assertNotReleased();

        _renderAll = renderAll;
    }

    @Override
    public Collection<String> getExecuteIds() {
        assertNotReleased();

        if (_executeClientIds == null) {
            String executeMode = _facesContext.getExternalContext().
                    getRequestParameterMap().get(
                    PartialViewContext.PARTIAL_EXECUTE_PARAM_NAME);

            if (executeMode != null && !"".equals(executeMode) &&
                    //!PartialViewContext.NO_PARTIAL_PHASE_CLIENT_IDS.equals(executeMode) &&
                    !PartialViewContext.ALL_PARTIAL_PHASE_CLIENT_IDS.equals(executeMode)) {
               
                String[] clientIds = StringUtils.splitShortString(_replaceTabOrEnterCharactersWithSpaces(executeMode), ' ');

                //The collection must be mutable
                List<String> tempList = new ArrayList<String>();
                for (String clientId : clientIds)
                {
                    if (clientId.length() > 0)
                    {
                        tempList.add(clientId);
                    }
                }
                // The "javax.faces.source" parameter needs to be added to the list of
                // execute ids if missing (otherwise, we'd never execute an action associated
                // with, e.g., a button).
               
                String source = _facesContext.getExternalContext().getRequestParameterMap().get
                    (PartialViewContextImpl.SOURCE_PARAM_NAME);
               
                if (source != null)
                {
                    source = source.trim();
                   
                    if (!tempList.contains (source))
                    {
                        tempList.add (source);
                    }
                }
               
                _executeClientIds = tempList;
            } else {
                _executeClientIds = new ArrayList<String>();
            }
        }
        return _executeClientIds;
    }
   
    private String _replaceTabOrEnterCharactersWithSpaces(String mode)
    {
        StringBuilder builder = new StringBuilder(mode.length());
        for (int i = 0; i < mode.length(); i++)
        {
            if (mode.charAt(i) == '\t' ||
                mode.charAt(i) == '\n')
            {
                builder.append(' ');
            }
            else
            {
                builder.append(mode.charAt(i));
            }
        }
        return builder.toString();
    }

    @Override
    public Collection<String> getRenderIds() {
        assertNotReleased();

        if (_renderClientIds == null) {
            String renderMode = _facesContext.getExternalContext().
                    getRequestParameterMap().get(
                    PartialViewContext.PARTIAL_RENDER_PARAM_NAME);

            if (renderMode != null && !"".equals(renderMode) &&
                    //!PartialViewContext.NO_PARTIAL_PHASE_CLIENT_IDS.equals(renderMode) &&
                    !PartialViewContext.ALL_PARTIAL_PHASE_CLIENT_IDS.equals(renderMode))
            {
                String[] clientIds = StringUtils.splitShortString(_replaceTabOrEnterCharactersWithSpaces(renderMode), ' ');

                //The collection must be mutable
                List<String> tempList = new ArrayList<String>();
                for (String clientId : clientIds)
                {
                    if (clientId.length() > 0)
                    {
                        tempList.add(clientId);
                    }
                }
                _renderClientIds = tempList;
            } else {
                _renderClientIds = new ArrayList<String>();
               
                if (PartialViewContext.ALL_PARTIAL_PHASE_CLIENT_IDS.equals (renderMode))
                {
                    _renderClientIds.add (PartialResponseWriter.RENDER_ALL_MARKER);
                }
            }
        }
        return _renderClientIds;
    }

    @Override
    public PartialResponseWriter getPartialResponseWriter() {
        assertNotReleased();
       
        if (_partialResponseWriter == null)
        {
            ResponseWriter responseWriter = _facesContext.getResponseWriter();
            if (responseWriter == null)
            {
                // This case happens when getPartialResponseWriter() is called before
                // render phase, like in ExternalContext.redirect(). We have to create a
                // ResponseWriter from the RenderKit and then wrap if necessary.
                try
                {
                    RenderKit renderKit = _facesContext.getRenderKit();
                    if (renderKit == null)
                    {
                        // If the viewRoot was set to null by some reason, or there is no
                        // renderKitId on that view, this could be still an ajax redirect,
                        // so we have to try to calculate the renderKitId and return a
                        // RenderKit instance, to send the response.
                        String renderKitId = _facesContext.getApplication().getViewHandler().calculateRenderKitId(_facesContext);
                        RenderKitFactory rkf = (RenderKitFactory)FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
                        renderKit = rkf.getRenderKit(_facesContext, renderKitId);
                    }
                    responseWriter = renderKit.createResponseWriter(
                            _facesContext.getExternalContext().getResponseOutputWriter(), "text/xml",
                            _facesContext.getExternalContext().getRequestCharacterEncoding());
                }
                catch (IOException e)
                {
                    throw new IllegalStateException("Cannot create Partial Response Writer",e);
                }
            }
            // It is possible that the RenderKit return a PartialResponseWriter instance when
            // createResponseWriter,  so we should cast here for it and prevent double wrapping.
            if (responseWriter instanceof PartialResponseWriter)
            {
                _partialResponseWriter = (PartialResponseWriter) responseWriter;
            }
            else
            {
                _partialResponseWriter = new PartialResponseWriterImpl(responseWriter);
            }
        }
        return _partialResponseWriter;
    }

    /**
     * process the partial response
     * allowed phase ids according to the spec
     *
     *
     */
    @Override
    public void processPartial(PhaseId phaseId) {
        assertNotReleased();

        UIViewRoot viewRoot = _facesContext.getViewRoot();

        if (phaseId == PhaseId.APPLY_REQUEST_VALUES
                || phaseId == PhaseId.PROCESS_VALIDATIONS
                || phaseId == PhaseId.UPDATE_MODEL_VALUES)
        {
            processPartialExecute(viewRoot, phaseId);
        }
        else if (phaseId == PhaseId.RENDER_RESPONSE)
        {
            processPartialRendering(viewRoot, phaseId);
        }
    }

    private void processPartialExecute(UIViewRoot viewRoot, PhaseId phaseId)
    {
        PartialViewContext pvc = _facesContext.getPartialViewContext();
        Collection<String> executeIds = pvc.getExecuteIds();
        if (executeIds == null || executeIds.isEmpty())
        {
            return;
        }
        Set<VisitHint> hints = new HashSet<VisitHint>();
        hints.add(VisitHint.EXECUTE_LIFECYCLE);
        hints.add(VisitHint.SKIP_UNRENDERED);
        VisitContext visitCtx = VisitContext.createVisitContext(_facesContext, executeIds, hints);
        viewRoot.visitTree(visitCtx, new PhaseAwareVisitCallback(_facesContext, phaseId));
    }

    private void processPartialRendering(UIViewRoot viewRoot, PhaseId phaseId)
    {
        //TODO process partial rendering
        //https://issues.apache.org/jira/browse/MYFACES-2118
        //Collection<String> renderIds = getRenderIds();
       
        // We need to always update the view state marker when processing partial
        // rendering, because there is no way to check when the state has been changed
        // or not. Anyway, if we return empty response, according to the spec a javascript
        // message displayed, so we need to return something.
        //if (renderIds == null || renderIds.isEmpty()) {
        //    return;
        //}

        // note that we cannot use this.getPartialResponseWriter(), because
        // this could cause problems if PartialResponseWriter is wrapped
        PartialResponseWriter writer = _facesContext.getPartialViewContext().getPartialResponseWriter();
        PartialViewContext pvc = _facesContext.getPartialViewContext();
       
        ResponseWriter oldWriter = _facesContext.getResponseWriter();
        boolean inDocument = false;

        //response type = text/xml
        //no caching and no timeout if possible!
        ExternalContext externalContext = _facesContext.getExternalContext();
        externalContext.setResponseContentType("text/xml");
        externalContext.addResponseHeader("Pragma", "no-cache");
        externalContext.addResponseHeader("Cache-control", "no-cache");
        //under normal circumstances pragma should be enough, IE needs
        //a special treatment!
        //http://support.microsoft.com/kb/234067
        externalContext.addResponseHeader("Expires", "-1");

        try
        {
            writer.startDocument();
            inDocument = true;
            _facesContext.setResponseWriter(writer);

            if (pvc.isRenderAll())
            {
                processRenderAll(viewRoot, writer);
            }
            else
            {
                Collection<String> renderIds = pvc.getRenderIds();
                //Only apply partial visit if we have ids to traverse
                if (renderIds != null && !renderIds.isEmpty())
                {
                    Set<VisitHint> hints = new HashSet<VisitHint>();
                    // unrendered have to be skipped, transient definitely must be added to our list!
                    hints.add(VisitHint.SKIP_UNRENDERED);
                   
                    // render=@all, so output the body.
                    if (renderIds.contains (PartialResponseWriter.RENDER_ALL_MARKER))
                    {
                        processRenderAll(viewRoot, writer);
                    }
                    else
                    {
                        VisitContext visitCtx = VisitContext.createVisitContext(_facesContext, renderIds, hints);
                        viewRoot.visitTree(visitCtx, new PhaseAwareVisitCallback(_facesContext, phaseId));
                    }
                }
            }
           
            // invoke encodeAll() on every UIViewParameter in the view to
            // enable every UIViewParameter to save its value in the state
            // just like UIViewRoot.encodeEnd() does on a normal request
            // (see MYFACES-2645 for details)
            Collection<UIViewParameter> viewParams = ViewMetadata.getViewParameters(viewRoot);   
            if (!viewParams.isEmpty())
            {
                for (UIViewParameter param : viewParams)
                {
                    param.encodeAll(_facesContext);
                }
            }
           
            //Retrieve the state and apply it if it is not null.
            String viewState = _facesContext.getApplication().getStateManager().getViewState(_facesContext);
            if (viewState != null)
            {
                writer.startUpdate(PartialResponseWriter.VIEW_STATE_MARKER);
                writer.write(viewState);
                writer.endUpdate();
            }
        } catch (IOException ex) {
            Logger log = Logger.getLogger(PartialViewContextImpl.class.getName());
            if (log.isLoggable(Level.SEVERE)) {
                log.log(Level.SEVERE, "" , ex);
            }

        } finally {
            try {
                if (inDocument) {
                    writer.endDocument();
                }
                writer.flush();
            } catch (IOException ex) {
                Logger log = Logger.getLogger(PartialViewContextImpl.class.getName());
                if (log.isLoggable(Level.SEVERE)) {
                    log.log(Level.SEVERE, "" , ex);
                }
            }

            _facesContext.setResponseWriter(oldWriter);
        }

    }
   
    private void processRenderAll(UIViewRoot viewRoot, PartialResponseWriter writer) throws IOException
    {
        //java.util.Iterator<UIComponent> iter = viewRoot.getFacetsAndChildren();
        writer.startUpdate (PartialResponseWriter.RENDER_ALL_MARKER);
        //while (iter.hasNext())
        //{
            //UIComponent comp = iter.next();
           
            //TODO: Do not check for a specific instance,
            //just render all children.
            //if (comp instanceof javax.faces.component.html.HtmlBody)
            //{
                //comp.encodeAll (_facesContext);
            //}
        //}
        for (UIComponent comp : viewRoot.getChildren())
        {
            comp.encodeAll (_facesContext);
        }
        writer.endUpdate();
    }

    /**
     * has to be thrown in many of the methods if the method is called after the instance has been released!
     */
    private void assertNotReleased() {
        if (_released) {
            throw new IllegalStateException("Error the FacesContext is already released!");
        }
    }

    @Override
    public void release() {
        assertNotReleased();
        _executeClientIds = null;
        _renderClientIds = null;
        _ajaxRequest = null;
        _partialRequest = null;
        _renderAll = null;
        _facesContext = null;
        _released = true;
    }

    private class PhaseAwareVisitCallback implements VisitCallback {

        private PhaseId _phaseId;
        private FacesContext _facesContext;

        public PhaseAwareVisitCallback(FacesContext facesContext, PhaseId phaseId) {
            this._phaseId = phaseId;
            this._facesContext = facesContext;
        }

        public VisitResult visit(VisitContext context, UIComponent target) {
            if (_phaseId == PhaseId.APPLY_REQUEST_VALUES) {
                target.processDecodes(_facesContext);
            } else if (_phaseId == PhaseId.PROCESS_VALIDATIONS) {
                target.processValidators(_facesContext);
            } else if (_phaseId == PhaseId.UPDATE_MODEL_VALUES) {
                target.processUpdates(_facesContext);
            } else if (_phaseId == PhaseId.RENDER_RESPONSE) {
                processRenderComponent(target);
            } else {
                throw new IllegalStateException("PPR Response, illegale phase called");
            }

            // Return VisitResult.REJECT as processDecodes/Validators/Updates already traverse sub tree
            return VisitResult.REJECT;
        }

        /**
         * the rendering subpart of the tree walker
         * every component id which is passed down via render must be handled
         * here!
         *
         * @param target the target component to be handled!
         */
        private void processRenderComponent(UIComponent target) {
            boolean inUpdate = false;
            PartialResponseWriter writer = (PartialResponseWriter) _facesContext.getResponseWriter();
            try {
                writer.startUpdate(target.getClientId(_facesContext));
                inUpdate = true;
                target.encodeAll(_facesContext);
            } catch (IOException ex) {
                Logger log = Logger.getLogger(PartialViewContextImpl.class.getName());
                if (log.isLoggable(Level.SEVERE)) {
                    log.log(Level.SEVERE, "IOException for rendering component", ex);
                }
            } finally {
                if (inUpdate) {
                    try {
                        writer.endUpdate();
                    } catch (IOException ex) {
                        Logger log = Logger.getLogger(PartialViewContextImpl.class.getName());
                        if (log.isLoggable(Level.SEVERE)) {
                            log.log(Level.SEVERE, "IOException for rendering component, stopping update rendering", ex);
                        }
                    }
                }
            }
        }
    }
}
TOP

Related Classes of org.apache.myfaces.context.servlet.PartialViewContextImpl$PhaseAwareVisitCallback

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.