Thanks for adding this, Ed. Would you please update the snapshot? It
looks like the last posting was Aug 4th.
Dan
Ed Burns wrote:
>>>>>> On Wed, 16 Aug 2006 10:44:56 -0400, jacob_at_hookom.net said:
>>>>>>
>
> JH> I don't know if you are running into troubled waters here by
> JH> temporarily changing component state. The point of avatar was
> JH> to process the component model in the most natural and external way
> JH> possible. Dan does bring up an interesting use case where the
> JH> component event fired internally decides to change some state which
> JH> you've asserted ownership over.
>
> Yes, I too am a little skittish about it. However, I have checked it in
> and it does only modify the state if it's not already immediate, and the
> component is guaranteed to be reset back to its initial state due to the
> finally block. I'm pretty confident this is ok.
>
> https://jsf-extensions.dev.java.net/issues/show_bug.cgi?id=7
>
> Here is the change-bundle.
>
> This feature provides an "immediate" option to the associative array
> that is last argument to DynaFaces.installDeferredAjaxTransaction() and
> DynaFaces.fireAjaxTransaction().
>
> This option has the effect of setting the immediate property to true for
> the components affected by this ajax transaction to true for this
> transaction only. If a component is already marked as immediate, its
> immediate property is unchanged.
>
> M run-time/samples/simple-partial-update/src/main/java/test/TestBean.java
>
> - add immediateButtonIsImmediate property that tells if the button with
> id "immediate" has its immediate value to true or false. It should be
> false.
>
> M run-time/samples/simple-partial-update/src/main/webapp/home.jsp
>
> - Demonstrate the "immediate" option.
>
> M run-time/common/src/main/java/com/sun/faces/extensions/common/util/Util.java
>
> - Copy over "prefixViewTraversal" to Util from Sun Impl.
>
> M run-time/avatar/src/main/java/com/sun/faces/extensions/avatar/lifecycle/PartialTraversalLifecycle.java
>
> - add finally block around call to parent.execute() that calls
> viewRoot.postExecuteCleanup().
>
> M run-time/avatar/src/main/java/com/sun/faces/extensions/avatar/lifecycle/AsyncResponse.java
>
> - add immediateAjaxRequest property.
>
> M run-time/avatar/src/main/java/com/sun/faces/extensions/avatar/components/PartialTraversalViewRoot.java
>
> - mark components as immediate if this transaction is marked to be
> immediate.
>
> M run-time/avatar/src/main/resources/com_sun_faces_ajax.js
>
> - Fix a bug where viewState values were incorrectly being concatenated.
>
> M pom.xml
>
> - add master-pom to samples.
>
> SECTION: Diffs
>
> Index: run-time/samples/simple-partial-update/src/main/java/test/TestBean.java
> ===================================================================
> --- run-time/samples/simple-partial-update/src/main/java/test/TestBean.java (revision 190)
> +++ run-time/samples/simple-partial-update/src/main/java/test/TestBean.java (working copy)
> @@ -5,11 +5,9 @@
>
> package test;
>
> -import com.sun.faces.extensions.avatar.lifecycle.AsyncResponse;
> -import java.util.ArrayList;
> -import java.util.List;
> +import javax.faces.component.ActionSource;
> +import javax.faces.component.ContextCallback;
> import javax.faces.component.UIComponent;
> -import javax.faces.component.UIData;
> import javax.faces.context.FacesContext;
> import javax.faces.event.ActionEvent;
>
> @@ -45,6 +43,24 @@
> public void setText(String text) {
> this.text = text;
> }
> +
> + /**
> + * Getter for property immediateButtonImmediate.
> + * @return Value of property immediateButtonImmediate.
> + */
> + public boolean isImmediateButtonIsImmediate() {
> + FacesContext context = FacesContext.getCurrentInstance();
> + final boolean [] result = new boolean[1];
> + result[0] = false;
> +
> + context.getViewRoot().invokeOnComponent(context, "immediate", new ContextCallback() {
> + public void invokeContextCallback(FacesContext facesContext, UIComponent comp) {
> + result[0] = ((ActionSource)comp).isImmediate();
> + }
> + });
> +
> + return result[0];
> + }
>
>
>
> Index: run-time/samples/simple-partial-update/src/main/webapp/home.jsp
> ===================================================================
> --- run-time/samples/simple-partial-update/src/main/webapp/home.jsp (revision 190)
> +++ run-time/samples/simple-partial-update/src/main/webapp/home.jsp (working copy)
> @@ -42,11 +42,37 @@
>
> </tr>
>
> +<tr>
> +
> +<td>Same as above but with <code>immediate</code> set to
> +<code>true</code> <i>for this request only</i>.</td>
> +
> +<td><h:commandButton id="immediate" actionListener="#{testBean.changeText}"
> + value="submit immediate"/>
> +</td>
> +
> +</tr>
> +
> +<tr>
> +
> +<td>Value of <code>immediate</code> property of "submit immediate" button.
> +</td>
> +
> +<td><code><h:outputText value="#{testBean.immediateButtonIsImmediate}" /></code>
> +</td>
> +
> +</tr>
> +
> +
> </table>
>
> </h:form>
> <script type='text/javascript'>
> DynaFaces.installDeferredAjaxTransaction($('button'), 'click');
> + DynaFaces.installDeferredAjaxTransaction($('immediate'), 'click', {
> + execute: "immediate",
> + immediate: true
> + });
> </script>
>
>
> Index: run-time/common/src/main/java/com/sun/faces/extensions/common/util/Util.java
> ===================================================================
> --- run-time/common/src/main/java/com/sun/faces/extensions/common/util/Util.java (revision 190)
> +++ run-time/common/src/main/java/com/sun/faces/extensions/common/util/Util.java (working copy)
> @@ -25,7 +25,9 @@
>
> package com.sun.faces.extensions.common.util;
>
> +import java.util.Iterator;
> import java.util.List;
> +import javax.faces.FacesException;
> import javax.faces.FactoryFinder;
> import javax.faces.application.Application;
> import javax.faces.component.UIComponent;
> @@ -137,4 +139,25 @@
> RenderKit curRenderKit = fact.getRenderKit(context, renderKitId);
> return curRenderKit;
> }
> +
> + public static boolean prefixViewTraversal(FacesContext context,
> + UIComponent root,
> + TreeTraversalCallback action) throws FacesException {
> + boolean keepGoing = false;
> + if (keepGoing = action.takeActionOnNode(context, root)) {
> + Iterator<UIComponent> kids = root.getFacetsAndChildren();
> + while (kids.hasNext() && keepGoing) {
> + keepGoing = prefixViewTraversal(context,
> + kids.next(),
> + action);
> + }
> + }
> + return keepGoing;
> + }
> +
> + public static interface TreeTraversalCallback {
> + public boolean takeActionOnNode(FacesContext context,
> + UIComponent curNode) throws FacesException;
> + }
> +
> }
> Index: run-time/avatar/src/main/java/com/sun/faces/extensions/avatar/lifecycle/PartialTraversalLifecycle.java
> ===================================================================
> --- run-time/avatar/src/main/java/com/sun/faces/extensions/avatar/lifecycle/PartialTraversalLifecycle.java (revision 190)
> +++ run-time/avatar/src/main/java/com/sun/faces/extensions/avatar/lifecycle/PartialTraversalLifecycle.java (working copy)
> @@ -75,7 +75,12 @@
> // portion of the lifecycle.
> async.setOnOffResponseEnabled(true);
> }
> - parent.execute(context);
> + try {
> + parent.execute(context);
> + }
> + finally {
> + ((PartialTraversalViewRoot)context.getViewRoot()).postExecuteCleanup(context);
> + }
> }
>
> public void render(FacesContext context) throws FacesException {
> Index: run-time/avatar/src/main/java/com/sun/faces/extensions/avatar/lifecycle/AsyncResponse.java
> ===================================================================
> --- run-time/avatar/src/main/java/com/sun/faces/extensions/avatar/lifecycle/AsyncResponse.java (revision 190)
> +++ run-time/avatar/src/main/java/com/sun/faces/extensions/avatar/lifecycle/AsyncResponse.java (working copy)
> @@ -314,7 +314,32 @@
> }
> return result;
> }
> +
> + /**
> + * <p>Return <code>true</code> if and only if the request headers include
> + * an entry for {_at_link #PARTIAL_HEADER} and the value for that header is
> + * <code>immediate</code>. Otherwise return <code>false</code>.
> + */
>
> + public static boolean isImmediateAjaxRequest() {
> + ExternalContext ext = FacesContext.getCurrentInstance().getExternalContext();
> + Map<String, Object> requestMap = ext.getRequestMap();
> + final String immediateFlag = FACES_PREFIX + "IsImmediate";
> + if (requestMap.containsKey(immediateFlag)) {
> + return true;
> + }
> +
> + Map<String, String> p = ext.getRequestHeaderMap();
> + String partialValue = p.get(PARTIAL_HEADER);
> + boolean result = false;
> + if (null != partialValue) {
> + result = partialValue.equalsIgnoreCase("immediate");
> + }
> + if (result) {
> + requestMap.put(immediateFlag, Boolean.TRUE);
> + }
> + return result;
> + }
> private Object origResponse = null;
>
> /**
> Index: run-time/avatar/src/main/java/com/sun/faces/extensions/avatar/components/PartialTraversalViewRoot.java
> ===================================================================
> --- run-time/avatar/src/main/java/com/sun/faces/extensions/avatar/components/PartialTraversalViewRoot.java (revision 190)
> +++ run-time/avatar/src/main/java/com/sun/faces/extensions/avatar/components/PartialTraversalViewRoot.java (working copy)
> @@ -31,13 +31,17 @@
>
> import com.sun.faces.extensions.avatar.event.EventParser;
> import com.sun.faces.extensions.avatar.lifecycle.AsyncResponse;
> +import com.sun.faces.extensions.common.util.Util;
> import java.io.IOException;
> import java.io.Serializable;
> +import java.util.ArrayList;
> import java.util.Iterator;
> import java.util.List;
> import javax.faces.FacesException;
> import javax.faces.application.FacesMessage;
> +import javax.faces.component.ActionSource;
> import javax.faces.component.ContextCallback;
> +import javax.faces.component.EditableValueHolder;
> import javax.faces.component.UIComponent;
> import javax.faces.component.UIViewRoot;
> import javax.faces.component.UIViewRootCopy;
> @@ -129,19 +133,73 @@
> public class PartialTraversalViewRoot extends UIViewRootCopy implements Serializable {
>
> public PartialTraversalViewRoot() {
> + modifiedComponents = new ArrayList<UIComponent>();
> +
> + markImmediate = new Util.TreeTraversalCallback() {
> + public boolean takeActionOnNode(FacesContext context, UIComponent comp) throws FacesException {
> + if (comp instanceof ActionSource) {
> + ActionSource as = (ActionSource)comp;
> + if (!as.isImmediate()) {
> + as.setImmediate(true);
> + modifiedComponents.add(comp);
> + }
> + } else if (comp instanceof EditableValueHolder) {
> + EditableValueHolder ev = (EditableValueHolder)comp;
> + if (!ev.isImmediate()) {
> + ev.setImmediate(true);
> + modifiedComponents.add(comp);
> + }
> + }
> +
> + return true;
> + }
> +
> + };
> }
>
> + private transient List<UIComponent> modifiedComponents;
> +
> + private transient Util.TreeTraversalCallback markImmediate;
> +
> + public void postExecuteCleanup(FacesContext context) {
> + for (UIComponent comp : modifiedComponents) {
> + if (comp instanceof ActionSource) {
> + ActionSource as = (ActionSource)comp;
> + assert(as.isImmediate());
> + as.setImmediate(false);
> + } else if (comp instanceof EditableValueHolder) {
> + EditableValueHolder ev = (EditableValueHolder)comp;
> + assert(ev.isImmediate());
> + ev.setImmediate(false);
> + }
> + }
> + modifiedComponents.clear();
> + }
> +
> public void processDecodes(FacesContext context) {
> boolean invokedCallback = false;
> if (!AsyncResponse.isAjaxRequest()) {
> super.processDecodes(context);
> return;
> }
> + AsyncResponse async = AsyncResponse.getInstance();
> + modifiedComponents.clear();
> +
> + // If this is an immediate "render all" request and there are
> + // no explicit execute subtrees and the user didn't request
> + // execute: none...
> + if (async.isImmediateAjaxRequest() && async.isRenderAll() &&
> + async.getExecuteSubtrees().isEmpty() &&
> + !async.isExecuteNone()) {
> + // Traverse the entire view and mark every ActionSource or
> + // EditableValueHolder as immediate.
> + Util.prefixViewTraversal(context, this, markImmediate);
> + }
> +
> invokedCallback = invokeContextCallbackOnSubtrees(context,
> new PhaseAwareContextCallback(PhaseId.APPLY_REQUEST_VALUES));
>
> // Queue any events for this request in a context aware manner
> - AsyncResponse async = AsyncResponse.getInstance();
> ResponseWriter writer = null;
> try {
> writer = async.getResponseWriter();
> @@ -384,15 +442,18 @@
> ConverterException converterException = null;
>
> if (curPhase == PhaseId.APPLY_REQUEST_VALUES) {
> + // If the user requested an immediate request
> + // Make sure to set the immediate flag.
> + if (AsyncResponse.isImmediateAjaxRequest()) {
> + PartialTraversalViewRoot.this.markImmediate.takeActionOnNode(facesContext, comp);
> + }
> +
> comp.processDecodes(facesContext);
> - }
> - else if (curPhase == PhaseId.PROCESS_VALIDATIONS) {
> + } else if (curPhase == PhaseId.PROCESS_VALIDATIONS) {
> comp.processValidators(facesContext);
> - }
> - else if (curPhase == PhaseId.UPDATE_MODEL_VALUES) {
> + } else if (curPhase == PhaseId.UPDATE_MODEL_VALUES) {
> comp.processUpdates(facesContext);
> - }
> - else if (curPhase == PhaseId.RENDER_RESPONSE) {
> + } else if (curPhase == PhaseId.RENDER_RESPONSE) {
> ResponseWriter writer = AsyncResponse.getInstance().getResponseWriter();
>
> writer.startElement("render", comp);
> Index: run-time/avatar/src/main/resources/com_sun_faces_ajax.js
> ===================================================================
> --- run-time/avatar/src/main/resources/com_sun_faces_ajax.js (revision 190)
> +++ run-time/avatar/src/main/resources/com_sun_faces_ajax.js (working copy)
> @@ -347,7 +347,8 @@
> if (p[1].constructor != Array) {
> p[1] = [p[1]];
> }
> - if (this[p[0]]) {
> + // Don't concatenate the viewState.
> + if (this[p[0]] && -1 == gViewState.indexOf(p[0])) {
> this[p[0]] = this[p[0]].concat(p[1]);
> }
> else {
> @@ -481,7 +482,12 @@
>
> // guarantee our header
> this.options.requestHeaders.push(gPartial);
> - this.options.requestHeaders.push('true');
> + if (this.options.immediate) {
> + this.options.requestHeaders.push('immediate');
> + }
> + else {
> + this.options.requestHeaders.push('true');
> + }
>
> // add methodName
> if (this.options.methodName) {
> Index: pom.xml
> ===================================================================
> --- pom.xml (revision 190)
> +++ pom.xml (working copy)
> @@ -145,12 +145,13 @@
> <profile>
> <id>samples</id>
> <modules>
> - <module>maven/master-pom</module>
> + <module>run-time/common</module>
> <module>run-time/avatar</module>
> <module>run-time/samples/j1</module>
> <module>run-time/samples/cardemo</module>
> <module>run-time/samples/jmaki</module>
> <module>run-time/samples/simple-events</module>
> + <module>run-time/samples/simple-partial-update</module>
> </modules>
> </profile>
> <profile>
>
>
>
>
>
>