Package org.openfaces.util

Source Code of org.openfaces.util.UtilPhaseListener

/*
* OpenFaces - JSF Component Library 2.0
* Copyright (C) 2007-2012, TeamDev Ltd.
* licensing@openfaces.org
* Unless agreed in writing the contents of this file are subject to
* the GNU Lesser General Public License Version 2.1 (the "LGPL" License).
* 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.
* Please visit http://openfaces.org/licensing/ for more details.
*/
package org.openfaces.util;

import org.openfaces.ajax.AjaxRequest;
import org.openfaces.component.OUIObjectIterator;
import org.openfaces.component.ajax.DefaultProgressMessage;
import org.openfaces.component.table.AbstractTable;
import org.openfaces.component.table.Columns;
import org.openfaces.component.table.impl.DynamicColumn;
import org.openfaces.event.AjaxActionEvent;
import org.openfaces.renderkit.ajax.DefaultProgressMessageRenderer;

import javax.el.ELContext;
import javax.el.MethodExpression;
import javax.el.MethodNotFoundException;
import javax.faces.FacesException;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIComponent;
import javax.faces.component.UIData;
import javax.faces.component.UIViewRoot;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.PhaseEvent;
import javax.faces.event.PhaseId;
import javax.portlet.faces.Bridge;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
* @author Dmitry Pikhulya
*/
public class UtilPhaseListener extends PhaseListenerBase {
    private static final String FOCUSED_COMPONENT_ID_KEY = UtilPhaseListener.class.getName() + ".focusedComponentId";
    private static final String FOCUS_TRACKER_FIELD_ID = "o::defaultFocus";
    private static final String FORCE_UTIL_JS_CONTEXT_PARAM = "org.openfaces.forceIncludingUtilJs";
    private static final String AUTO_FOCUS_TRACKING_CONTEXT_PARAM = "org.openfaces.autoSaveFocus";
    private static final String DISABLED_CONTEXT_MENU_CONTEXT_PARAM = "org.openfaces.disabledContextMenu";

    private static final String SCROLL_POS_KEY = UtilPhaseListener.class.getName() + ".pageScrollPos";
    private static final String SCROLL_POS_TRACKER_FIELD_ID = "o::defaultScrollPosition";
    private static final String AUTO_SCROLL_POS_TRACKING_CONTEXT_PARAM = "org.openfaces.autoSaveScrollPos";
    private static final String SUBMISSION_AJAX_INACTIVITY_TIMEOUT_CONTEXT_PARAM = "org.openfaces.submissionAjaxInactivityTimeout";
    private static final long DEFAULT_SUBMISSION_AJAX_INACTIVITY_TIMEOUT = 2000;

    public static final String PARAM_ACTION_COMPONENT = "_of_actionComponent";
    public static final String PARAM_ACTION_LISTENER = "_of_actionListener";
    public static final String PARAM_ACTION = "_of_action";
    public static final String PARAM_IMMEDIATE = "_of_immediate";

    public void beforePhase(PhaseEvent event) {
    }

    public void afterPhase(PhaseEvent event) {
        if (checkPortletMultipleNotifications(event, false))
            return;

        FacesContext context = event.getFacesContext();
        PhaseId phaseId = event.getPhaseId();
        if (phaseId.equals(PhaseId.RENDER_RESPONSE)) {
            List<String> renderedJsLinks = Resources.getRenderedJsLinks(context);
            String utilJs = Resources.utilJsURL(context);
            boolean renderFocusScript = isAutoFocusTrackingEnabled(context);
            boolean renderScrollingScript = isAutoScrollPosTrackingEnabled(context);
            boolean renderContextMenuScript = isDisabledContextMenuEnabled(context);
            if (!renderedJsLinks.contains(utilJs)) {
                if (renderFocusScript ||
                        renderScrollingScript ||
                        renderContextMenuScript ||
                        getForceIncludingUtilJs(context)) {
                    Resources.registerJavascriptLibrary(context, utilJs);
                }
            }
            if (renderFocusScript)
                Rendering.appendOnLoadScript(context, encodeFocusTracking(context));
            if (renderScrollingScript)
                Rendering.appendOnLoadScript(context, encodeScrollPosTracking(context));

            if (renderContextMenuScript)
                Rendering.appendOnLoadScript(context, encodeDisabledContextMenu(context));
            encodeAjaxProgressMessage(context);

            // Processing of Ajax requests as ResourceRequest is required under GateIn portal in order to
            // comply with existing navigationalState. This is important for RichFaces Ajax functionality
            if (Environment.isGateInPortal(context)) {
                String viewId = context.getViewRoot().getViewId();
                String ajaxRequestUrl = context.getApplication().getViewHandler().getActionURL(context, viewId);
                String encodedAjaxRequestUrl;

                if (null != context.getExternalContext().getRequestMap().get(Bridge.PORTLET_LIFECYCLE_PHASE)) {
                    ajaxRequestUrl = ajaxRequestUrl
                            + ((ajaxRequestUrl.lastIndexOf('?') > 0) ? "&" : "?")
                            + Bridge.FACES_VIEW_ID_PARAMETER + "=" + viewId;
                    encodedAjaxRequestUrl = context.getExternalContext().encodeResourceURL(ajaxRequestUrl);
                } else {
                    encodedAjaxRequestUrl = context.getExternalContext().encodeActionURL(ajaxRequestUrl);
                }

                Rendering.appendUniqueRTLibraryScripts(context, new ScriptBuilder().functionCall("O$._initAjaxRequestUrl", encodedAjaxRequestUrl).semicolon());

            }
        } else if (phaseId.equals(PhaseId.APPLY_REQUEST_VALUES)) {
            decodeFocusTracking(context);
            decodeScrollPosTracking(context);
        }
    }

    private void encodeAjaxProgressMessage(FacesContext context) {
        Map<String, Object> requestMap = context.getExternalContext().getRequestMap();

        if (requestMap.containsKey(DefaultProgressMessageRenderer.PROGRESS_MESSAGE)) {
            requestMap.put(DefaultProgressMessageRenderer.RENDERING, Boolean.TRUE);
            DefaultProgressMessage defaultProgressMessage = (DefaultProgressMessage) requestMap.get(DefaultProgressMessageRenderer.PROGRESS_MESSAGE);
            renderProgressMessage(context, defaultProgressMessage);
        } else if (requestMap.containsKey(AjaxUtil.AJAX_SUPPORT_RENDERED)) {
            DefaultProgressMessage defaultProgressMessage = new DefaultProgressMessage();
            renderProgressMessage(context, defaultProgressMessage);
        }
    }

    private void renderProgressMessage(FacesContext context, DefaultProgressMessage defaultProgressMessage) {
        try {
            defaultProgressMessage.encodeAll(context);
        } catch (IOException e) {
            throw new FacesException(e);
        }
    }

    private boolean getForceIncludingUtilJs(FacesContext context) {
        return Rendering.getBooleanContextParam(context, FORCE_UTIL_JS_CONTEXT_PARAM);
    }

    private boolean isAutoFocusTrackingEnabled(FacesContext context) {
        return Rendering.getBooleanContextParam(context, AUTO_FOCUS_TRACKING_CONTEXT_PARAM);
    }

    private boolean isDisabledContextMenuEnabled(FacesContext context) {
        return Rendering.getBooleanContextParam(context, DISABLED_CONTEXT_MENU_CONTEXT_PARAM);
    }

    private boolean isAutoScrollPosTrackingEnabled(FacesContext context) {
        return Rendering.getBooleanContextParam(context, AUTO_SCROLL_POS_TRACKING_CONTEXT_PARAM);
    }

    private Script encodeFocusTracking(FacesContext facesContext) {
        ExternalContext externalContext = facesContext.getExternalContext();
        Map requestMap = externalContext.getRequestMap();
        String focusedComponentId = (String) requestMap.get(FOCUSED_COMPONENT_ID_KEY);
        return new ScriptBuilder().functionCall("O$.initDefaultFocus",
                FOCUS_TRACKER_FIELD_ID,
                focusedComponentId != null ? focusedComponentId : null).semicolon();
    }

    private Script encodeScrollPosTracking(FacesContext facesContext) {
        ExternalContext externalContext = facesContext.getExternalContext();
        Map requestMap = externalContext.getRequestMap();
        String scrollPos = (String) requestMap.get(SCROLL_POS_KEY);
        return new ScriptBuilder().functionCall("O$.initDefaultScrollPosition",
                SCROLL_POS_TRACKER_FIELD_ID,
                scrollPos != null ? scrollPos : null).semicolon();
    }

    private Script encodeDisabledContextMenu(FacesContext facesContext) {
        return new RawScript("O$.disabledContextMenuFor(document);");
    }

    public static void encodeFormSubmissionAjaxInactivityTimeout(FacesContext context) {
        ExternalContext externalContext = context.getExternalContext();
        String paramStr = externalContext.getInitParameter(SUBMISSION_AJAX_INACTIVITY_TIMEOUT_CONTEXT_PARAM);

        long inactivityTimeout = DEFAULT_SUBMISSION_AJAX_INACTIVITY_TIMEOUT;
        if (paramStr != null) {
            try {
                final long parameterValue = Long.parseLong(paramStr);
                inactivityTimeout = Math.abs(parameterValue);
            } catch (NumberFormatException e) {
                externalContext.log("Invalid value specified for context parameter named " + SUBMISSION_AJAX_INACTIVITY_TIMEOUT_CONTEXT_PARAM
                        + ": it must be a number");
            }
        }

        final ScriptBuilder script = new ScriptBuilder("O$.setSubmissionAjaxInactivityTimeout(" + inactivityTimeout + ");");
        boolean isAjax4jsfRequest = AjaxUtil.isAjax4jsfRequest();
        boolean isPortletRequest = AjaxUtil.isPortletRequest(context);

        if (isAjax4jsfRequest || isPortletRequest) {
            try {
                Rendering.renderInitScript(context, script);
            }catch (Exception e){
                e.printStackTrace();
            }
        } else {
            Rendering.appendOnLoadScript(context, script);
        }

    }

    private void decodeFocusTracking(FacesContext facesContext) {
        if (!isAutoFocusTrackingEnabled(facesContext))
            return;
        ExternalContext externalContext = facesContext.getExternalContext();
        Map<String, String> requestParameterMap = externalContext.getRequestParameterMap();
        String focusedComponentId = requestParameterMap.get(FOCUS_TRACKER_FIELD_ID);
        Map<String, Object> requestMap = externalContext.getRequestMap();
        requestMap.put(FOCUSED_COMPONENT_ID_KEY, focusedComponentId);
    }

    private void decodeScrollPosTracking(FacesContext facesContext) {
        if (!isAutoScrollPosTrackingEnabled(facesContext))
            return;
        ExternalContext externalContext = facesContext.getExternalContext();
        Map<String, String> requestParameterMap = externalContext.getRequestParameterMap();
        String focusedComponentId = requestParameterMap.get(SCROLL_POS_TRACKER_FIELD_ID);
        Map<String, Object> requestMap = externalContext.getRequestMap();
        requestMap.put(SCROLL_POS_KEY, focusedComponentId);
    }


    public PhaseId getPhaseId() {
        return PhaseId.ANY_PHASE;
    }


    public static String processAjaxExecutePhase(FacesContext context, RequestFacade request, UIViewRoot viewRoot) {
        String listener = request.getParameter(PARAM_ACTION_LISTENER);
        String action = request.getParameter(PARAM_ACTION);
        String actionComponentId = request.getParameter(PARAM_ACTION_COMPONENT);
        if (listener != null || action != null) {
            ELContext elContext = context.getELContext();
            UIComponent component = null;
            List<Runnable> restoreDataPointerRunnables = new ArrayList<Runnable>();
            if (actionComponentId != null)
                component = findComponentById(viewRoot, actionComponentId, true, false, true, restoreDataPointerRunnables);
            if (component == null)
                component = viewRoot;

            Object result = null;
            if (action != null) {
                MethodExpression methodBinding = context.getApplication().getExpressionFactory().createMethodExpression(
                        elContext, "#{" + action + "}", String.class, new Class[]{});
                /*result = */
                methodBinding.invoke(elContext, null);
            }
            if (listener != null) {
                AjaxActionEvent event = new AjaxActionEvent(component);
                event.setPhaseId(Boolean.valueOf(request.getParameter(PARAM_IMMEDIATE)) ? PhaseId.APPLY_REQUEST_VALUES : PhaseId.INVOKE_APPLICATION);
                MethodExpression methodExpression = context.getApplication().getExpressionFactory().createMethodExpression(
                        elContext, "#{" + listener + "}", void.class, new Class[]{ActionEvent.class});
                try {
                    methodExpression.getMethodInfo(elContext);
                } catch (MethodNotFoundException e1) {
                    // both actionEvent and AjaxActionEvent parameter declarations are allowed
                    methodExpression = context.getApplication().getExpressionFactory().createMethodExpression(
                            elContext, "#{" + listener + "}", void.class, new Class[]{AjaxActionEvent.class});
                    try {
                        methodExpression.getMethodInfo(elContext);
                    } catch (MethodNotFoundException e2) {
                        Log.log("Couldn't find Ajax action handler method. Method expression: #{" + listener + "} . " +
                                "Note, the appropriate method should receive one parameter of either javax.faces.event.ActionEvent or " +
                                "org.openfaces.event.AjaxActionEvent type.", e2);
                        throw e2;
                    }
                }
                methodExpression.invoke(elContext, new Object[]{event});
                Object listenerResult = event.getAjaxResult();
                if (listenerResult != null)
                    result = listenerResult;
            }
            if (result != null)
                AjaxRequest.getInstance().setAjaxResult(result);
            for (Runnable restoreDataPointerRunnable : restoreDataPointerRunnables) {
                restoreDataPointerRunnable.run();
            }
        }
        return actionComponentId;
    }

    public static UIComponent findComponentById(UIComponent parent,
                                                String id,
                                                boolean preProcessDecodesOnTables,
                                                boolean preRenderResponseOnTables,
                                                boolean checkComponentPresence) {
        return findComponentById(parent, id, preProcessDecodesOnTables, preRenderResponseOnTables, checkComponentPresence, null);
    }

    public static UIComponent findComponentById(UIComponent parent,
                                                String id,
                                                boolean preProcessDecodesOnTables,
                                                boolean preRenderResponseOnTables,
                                                boolean checkComponentPresence,
                                                List<Runnable> restoreDataPointerRunnables) {
        FacesContext context = FacesContext.getCurrentInstance();
        if (Environment.isGateInPortal(context) && parent instanceof UIViewRoot) {
            String rootId = parent.getClientId(context);
            int idx = rootId.indexOf(parent.getId());
            String prefix = rootId.substring(0, idx);
            if (id.startsWith(prefix))
                id = id.substring(prefix.length());
        }

        UIComponent componentByPath = findComponentByPath(parent, id, preProcessDecodesOnTables,
                preRenderResponseOnTables, restoreDataPointerRunnables);
        if (checkComponentPresence && componentByPath == null)
            throw new FacesException("Component by id not found: " + id);
        return componentByPath;
    }

    private static UIComponent findComponentByPath(UIComponent parent,
                                                   String path,
                                                   boolean preProcessDecodesOnTables,
                                                   boolean preRenderResponseOnTables,
                                                   List<Runnable> restoreDataPointerRunnables) {
        while (true) {
            if (path == null) {
                return null;
            }

            int separator = path.indexOf(NamingContainer.SEPARATOR_CHAR, 1);
            if (separator == -1)
                return componentById(parent, path, true, preProcessDecodesOnTables,
                        preRenderResponseOnTables, restoreDataPointerRunnables);

            String id = path.substring(0, separator);
            UIComponent nextParent = componentById(parent, id, false, preProcessDecodesOnTables,
                    preRenderResponseOnTables, restoreDataPointerRunnables);
            if (nextParent == null) {
                return null;
            }
            parent = nextParent;
            path = path.substring(separator + 1);
        }
    }

    private static UIComponent componentById(UIComponent parent, String id, boolean isLastComponentInPath,
                                             boolean preProcessDecodesOnTables, boolean preRenderResponseOnTables,
                                             List<Runnable> restoreDataPointerRunnables) {
        FacesContext context = FacesContext.getCurrentInstance();
        if (id.length() > 0 && (isNumberBasedId(id) || id.startsWith(":")) && parent instanceof AbstractTable) {
            final AbstractTable table = ((AbstractTable) parent);
            if (!isLastComponentInPath) {
                if (preProcessDecodesOnTables)
                    table.invokeBeforeProcessDecodes(context);
                if (preRenderResponseOnTables) {
                    table.invokeBeforeRenderResponse(context);
                    table.setRowIndex(-1); // make the succeeding setRowIndex call provide the just-read actual row data through request-scope variables
                }

                int rowIndex = table.getRowIndexByClientSuffix(id);
                final int prevRowIndex = table.getRowIndex();
                if (prevRowIndex == rowIndex) {
                    // ensure row index setting will be run anew to ensure proper request-scope variable values
                    table.setRowIndex(-1);
                }
                table.setRowIndex(rowIndex);
                if (!table.isRowAvailable()) {
                    table.setRowIndex(-1);
                    String tableClientId = table.getClientId(context);
                    table.setRowIndex(prevRowIndex);
                    throw new IllegalStateException("Couldn't find table row for this Ajax request (row data for the requested row is missing). Table's clientId=" + tableClientId + "; rowIndex=" + rowIndex);
                }
                if (restoreDataPointerRunnables != null)
                    restoreDataPointerRunnables.add(new Runnable() {
                        public void run() {
                            table.setRowIndex(prevRowIndex);
                        }
                    });
            } else {
                int rowIndex = table.getRowIndexByClientSuffix(id);
                final int prevRowIndex = table.getRowIndex();
                if (prevRowIndex == rowIndex) {
                    // ensure row index setting will be run anew to ensure proper request-scope variable values
                    table.setRowIndex(-1);
                }
                table.setRowIndex(rowIndex);
                if (!table.isRowAvailable()) {
                    table.setRowIndex(-1);
                    String tableClientId = table.getClientId(context);
                    table.setRowIndex(prevRowIndex);
                    throw new IllegalStateException("Couldn't find table row for this Ajax request (row data for the requested row is missing). Table's clientId=" + tableClientId + "; rowIndex=" + rowIndex);
                }
                if (restoreDataPointerRunnables != null)
                    restoreDataPointerRunnables.add(new Runnable() {
                        public void run() {
                            table.setRowIndex(prevRowIndex);
                        }
                    });
            }
            return table;
        } else if (isNumberBasedId(id) && parent instanceof UIData) {
            final UIData uiData = ((UIData) parent);
            int rowIndex = Integer.parseInt(id);
            final int prevRowIndex = uiData.getRowIndex();
            uiData.setRowIndex(rowIndex);
            if (!uiData.isRowAvailable()) {
                uiData.setRowIndex(-1);
                String tableClientId = uiData.getClientId(context);
                uiData.setRowIndex(prevRowIndex);
                throw new IllegalStateException("Couldn't find UIData component row for this Ajax request (row data for the requested row is missing). Table's clientId=" + tableClientId + "; rowIndex=" + rowIndex);
            }

            if (restoreDataPointerRunnables != null)
                restoreDataPointerRunnables.add(new Runnable() {
                    public void run() {
                        uiData.setRowIndex(prevRowIndex);
                    }
                });
            return uiData;
        } else if (id.charAt(0) == ':' && parent instanceof OUIObjectIterator) {
            id = id.substring(1);
            final OUIObjectIterator iterator = (OUIObjectIterator) parent;
            final String prevObjectId = iterator.getObjectId();
            iterator.setObjectId(id);
            if (restoreDataPointerRunnables != null)
                restoreDataPointerRunnables.add(new Runnable() {
                    public void run() {
                        iterator.setObjectId(prevObjectId);
                    }
                });
            return (UIComponent) iterator;
        } else if (isNumberBasedId(id)) {
            Class clazz;
            try {
                clazz = Class.forName("com.sun.facelets.component.UIRepeat");
            } catch (ClassNotFoundException e) {
                clazz = null;
            }
            if (clazz != null && clazz.isInstance(parent)) {
                final Object uiRepeat = parent;
                ReflectionUtil.invokeMethod("com.sun.faces.facelets.component.UIRepeat", "setIndex",
                        new Class[]{Integer.TYPE}, new Object[]{Integer.parseInt(id)}, parent);
                if (restoreDataPointerRunnables != null)
                    restoreDataPointerRunnables.add(new Runnable() {
                        public void run() {
                            // there's no getIndex method in com.sun.faces.component.UIRepeat, so we can't restore
                            // the index in this way here
                        }
                    });
                return parent;
            } else if (parent instanceof Columns) {
                List<DynamicColumn> dynamicColumns = ((Columns) parent).toColumnList(context);
                int columnIndex = Integer.parseInt(id);
                final DynamicColumn dynamicColumn = dynamicColumns.get(columnIndex);
                final Runnable restoreVariables = dynamicColumn.enterComponentContext();
                if (restoreDataPointerRunnables != null)
                    restoreDataPointerRunnables.add(new Runnable() {
                        public void run() {
                            if (restoreVariables != null) restoreVariables.run();
                        }
                    });
                return parent;
            }
        }
        if (id.equals(parent.getId()))
            return parent;

        Iterator<UIComponent> iterator = parent.getFacetsAndChildren();
        while (iterator.hasNext()) {
            UIComponent child = iterator.next();
            Object prependId = child.getAttributes().get("prependId");
            if (child instanceof NamingContainer && !Boolean.FALSE.equals(prependId)) {
                if (id.equals(child.getId()))
                    return child;
            } else {
                UIComponent component = componentById(child, id,
                        isLastComponentInPath, preProcessDecodesOnTables, preRenderResponseOnTables,
                        restoreDataPointerRunnables);
                if (component != null)
                    return component;
            }
        }
        return null;
    }

    private static boolean isNumberBasedId(String id) {
        if (id == null || id.length() == 0)
            return false;

        char c = id.charAt(0);
        return Character.isDigit(c);
    }
}
TOP

Related Classes of org.openfaces.util.UtilPhaseListener

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.