All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.faces.ui.AjaxViewRoot Maven / Gradle / Ivy

There is a newer version: 3.0.0
Show newest version
/*
 * Copyright 2004-2008 the original author or authors.
 *
 * Licensed 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.springframework.faces.ui;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

import javax.faces.component.ContextCallback;
import javax.faces.component.UIComponent;
import javax.faces.component.UIForm;
import javax.faces.component.UIViewRoot;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.el.ValueBinding;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;
import javax.faces.event.PhaseId;
import javax.faces.lifecycle.Lifecycle;

import org.springframework.faces.ui.resource.ResourceHelper;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.webflow.execution.View;

/**
 * Customizes the behavior of an existing UIViewRoot with Ajax-aware processing.
 * 
 * 

* This component is the key to rendering partial subtrees of the JSF component tree. It makes use of JSF 1.2's * {@link UIComponent#invokeOnComponent(FacesContext, String, ContextCallback)} method to execute the various phases of * the {@link Lifecycle} on each subtree. *

* * @author Jeremy Grelle * @author Nazaret Kazarian */ public class AjaxViewRoot extends DelegatingViewRoot { public static final String AJAX_SOURCE_PARAM = "ajaxSource"; public static final String PROCESS_IDS_PARAM = "processIds"; protected static final String FORM_RENDERED = "formRendered"; protected static final String PROCESS_ALL = "*"; private List events = new ArrayList(); private String[] processIds; private String[] renderIds; private static final String RENDER_IDS_EXPRESSION = "#{" + View.RENDER_FRAGMENTS_ATTRIBUTE + "}"; private final ValueBinding renderIdsExpr; public AjaxViewRoot(UIViewRoot original) { super(original); renderIdsExpr = FacesContext.getCurrentInstance().getApplication().createValueBinding(RENDER_IDS_EXPRESSION); if (!StringUtils.hasText(original.getId())) { original.setId(createUniqueId()); } swapChildren(original, this); } // implementing view root public String getId() { return getOriginalViewRoot().getId() + "_ajax"; } public void queueEvent(FacesEvent event) { Assert.notNull(event, "Cannot queue a null event."); events.add(event); } public void encodeAll(FacesContext context) throws IOException { for (int i = 0; i < getRenderIds().length; i++) { String renderId = getRenderIds()[i]; ContextCallback callback = new ContextCallback() { public void invokeContextCallback(FacesContext context, UIComponent target) { try { target.encodeAll(context); if (target instanceof UIForm) { context.getViewRoot().getAttributes().put(FORM_RENDERED, FORM_RENDERED); } } catch (IOException e) { e.printStackTrace(); } } }; invokeOnComponent(context, renderId, callback); } swapChildren(this, getOriginalViewRoot()); context.setViewRoot(getOriginalViewRoot()); if (!getAttributes().containsKey(FORM_RENDERED)) { context.getApplication().getViewHandler().writeState(context); updateFormAction(context); } broadCastEvents(context, PhaseId.APPLY_REQUEST_VALUES); } public void processDecodes(FacesContext context) { for (int i = 0; i < getProcessIds().length; i++) { String processId = getProcessIds()[i]; ContextCallback callback = new ContextCallback() { public void invokeContextCallback(FacesContext context, UIComponent target) { target.processDecodes(context); } }; invokeOnComponent(context, processId, callback); } broadCastEvents(context, PhaseId.APPLY_REQUEST_VALUES); } public void processUpdates(FacesContext context) { for (int i = 0; i < getProcessIds().length; i++) { String processId = getProcessIds()[i]; ContextCallback callback = new ContextCallback() { public void invokeContextCallback(FacesContext context, UIComponent target) { target.processUpdates(context); } }; invokeOnComponent(context, processId, callback); } broadCastEvents(context, PhaseId.UPDATE_MODEL_VALUES); } public void processValidators(FacesContext context) { for (int i = 0; i < getProcessIds().length; i++) { String processId = getProcessIds()[i]; ContextCallback callback = new ContextCallback() { public void invokeContextCallback(FacesContext context, UIComponent target) { target.processValidators(context); } }; invokeOnComponent(context, processId, callback); } broadCastEvents(context, PhaseId.PROCESS_VALIDATIONS); } public void processApplication(FacesContext context) { broadCastEvents(context, PhaseId.INVOKE_APPLICATION); } // subclassing hooks protected String[] getProcessIds() { if (processIds == null) { FacesContext context = FacesContext.getCurrentInstance(); String processIdsParam = (String) context.getExternalContext().getRequestParameterMap().get( PROCESS_IDS_PARAM); if (StringUtils.hasText(processIdsParam) && processIdsParam.indexOf(PROCESS_ALL) != -1) { processIds = new String[] { getOriginalViewRoot().getClientId(context) }; } else { processIds = StringUtils.delimitedListToStringArray(processIdsParam, ",", " "); processIds = removeNestedChildren(context, processIds); } } return processIds; } protected String[] getRenderIds() { if (renderIds == null) { FacesContext context = FacesContext.getCurrentInstance(); renderIds = (String[]) renderIdsExpr.getValue(context); if (renderIds == null || renderIds.length == 0) { renderIds = getProcessIds(); } else { renderIds = removeNestedChildren(context, renderIds); } } return renderIds; } // internal helpers private void swapChildren(UIViewRoot source, UIViewRoot target) { target.getChildren().addAll(source.getChildren()); // Create a new list because the children of ViewRoot can change while we're iterating. // For example: // 1. child is an outputScript component with target="head" // 2. child.setParent() fires PostAddToViewEvent // 3. MyFaces HtmlScriptRenderer processes the event // 3.1. creates javax.faces.Panel for "head" // 3.2. adds outputScript to it // 3.3. the parent of outputScript is changed from ViewRoot to "head" Panel component // 4. outputScript is therefore no longer a child of ViewRoot List children = new ArrayList(target.getChildren()); for (int i = 0; i < children.size(); i++) { UIComponent child = (UIComponent) children.get(i); child.setParent(target); } } private void updateFormAction(FacesContext context) { ResponseWriter writer = context.getResponseWriter(); try { String formId = findContainingFormId(context); if (StringUtils.hasLength(formId)) { String script = "dojo.byId('" + formId + "').action = '" + context.getApplication().getViewHandler().getActionURL(context, getViewId()) + "'"; ResourceHelper.beginScriptBlock(context); writer.writeText(script, null); ResourceHelper.endScriptBlock(context); } } catch (IOException e) { e.printStackTrace(); } } private String findContainingFormId(FacesContext context) { for (int i = 0; i < getRenderIds().length; i++) { UIComponent component = context.getViewRoot().findComponent(getRenderIds()[i]); Assert.notNull(component, "Component to be rendered with id '" + getRenderIds()[i] + "' could not be found."); while (!(component instanceof UIViewRoot)) { component = component.getParent(); if (component instanceof UIForm) { return component.getClientId(context); } } } return null; } private String[] removeNestedChildren(FacesContext context, String[] ids) { List idList = Arrays.asList(ids); final List trimmedIds = new ArrayList(idList); for (final ListIterator i = trimmedIds.listIterator(); i.hasNext();) { String id = (String) i.next(); invokeOnComponent(context, id, new ContextCallback() { public void invokeContextCallback(FacesContext context, UIComponent component) { while (!(component.getParent() instanceof UIViewRoot)) { component = component.getParent(); if (trimmedIds.contains(component.getClientId(context))) { i.remove(); } } } }); } return (String[]) trimmedIds.toArray(new String[trimmedIds.size()]); } private void broadCastEvents(FacesContext context, PhaseId phaseId) { List processedEvents = new ArrayList(); if (events.size() == 0) return; boolean abort = false; int phaseIdOrdinal = phaseId.getOrdinal(); Iterator i = events.iterator(); while (i.hasNext()) { FacesEvent event = (FacesEvent) i.next(); int ordinal = event.getPhaseId().getOrdinal(); if (ordinal == PhaseId.ANY_PHASE.getOrdinal() || ordinal == phaseIdOrdinal) { UIComponent source = event.getComponent(); try { processedEvents.add(event); source.broadcast(event); } catch (AbortProcessingException e) { abort = true; break; } } } if (abort) { events.clear(); } else { events.removeAll(processedEvents); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy