4 Replies Latest reply on Oct 2, 2007 6:59 PM by Alexander Smirnov

    AjaxViewRoot implementation of javax.faces.ViewRoot

    Curtis Crabb Newbie

      As soon as I start using Shale 1.0.4, Ajax4Jsf stops working. I believe the issue is as follows:

      1.) Ajax4Jsf depends upon the javax.faces.ViewRoot being an instance of AjaxViewRoot.
      2.) Shale depends upon the javax.faces.ViewRoot being an instance of ShaleViewRoot.

      I believe I am correct in saying that my application can only use one implementation of javax.faces.ViewRoot; the one being used in my case is simply the last jar that is being loaded (on top of that, I can specify my own ViewRoot in my WEB-INF faces-config and then niether AjaxViewRoot or ShaleViewRoot will be used). That being the case, is it even possible to use both Ajax4Jsf and Shale in the same application?

      Can anyone shed some light on my confusion? Is this simply a design flaw of JSF? Why does Ajax4Jsf override the ViewRoot implementation when that immediately stops me from using other 3rd party products that override ViewRoot?

        • 1. Re: AjaxViewRoot implementation of javax.faces.ViewRoot
          Curtis Crabb Newbie

          A bit of extra information:

          Shale 1.0.3 does not provide it's own implementation of javax.faces.ViewRoot; that being the case, I can successfully use it with ajax4jsf.

          Also, I can use Shale 1.0.4 with ajax4jsf if I specify in the following in my own WEB-INF faces-config

          <component>
           <component-type>javax.faces.ViewRoot</component-type>
           <component-class>org.ajax4jsf.framework.ajax.AjaxViewRoot</component-class>
           <component-extension>
           <component-family>javax.faces.ViewRoot</component-family>
           </component-extension>
          </component>
          


          I believe this works simply because my copy of faces-config.xml is the last configuration loaded, so my override takes precedence.

          However, this can break Shale because now Shale sees an instance of AjaxViewRoot rather than ShaleViewRoot.

          So I am stuck with not knowing how to make both products work simultaneously.


          • 2. Re: AjaxViewRoot implementation of javax.faces.ViewRoot
            Alexander Smirnov Master

            AjaxViewRoot is a important part of the AJAX requests processing. Where is a control code for a partial page processing.
            On other hand, ShaleViewRoot is only add specific exception handling to standart UIViewRoot component. This is a simplest workaround :
            1) You can create AjaxShaleViewRoot component from original ShaleViewRoot code, but inherit it from AjaxViewRoot class :

            /*
             * 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 foo.bar;
            
            import javax.faces.component.UIViewRoot;
            import javax.faces.context.FacesContext;
            
            import org.ajax4jsf.component.AjaxViewRoot;
            
            import org.apache.shale.view.Constants;
            import org.apache.shale.view.ExceptionHandler;
            
            /**
             * <p>Extending the UIViewRoot to provide specialized exception
             * handling needed for the Shale view controller to enforce the contracts
             * of the callbacks.</p>
             */
            public class AjaxShaleViewRoot extends AjaxViewRoot {
            
             /**
             * <p>Override to catch exceptions raised by the action listeners
             * in the invoke application phase.</p>
             *
             * @param context faces context
             */
             public void processApplication(FacesContext context) {
             try {
             super.processApplication(context);
             } catch (Exception e) {
             handleException(context, e);
             context.responseComplete();
             }
             }
            
             /**
             * <p>Override to catch and handle exceptions with immediate commands
             * and value change listeners in the apply request values phase.</p>
             *
             * @param context faces context
             */
             public void processDecodes(FacesContext context) {
             try {
             super.processDecodes(context);
             } catch (Exception e) {
             handleException(context, e);
             context.responseComplete();
             }
             }
            
             /**
             * <p>Override to catch and handle exceptions raised in the
             * update model phase.</p>
             *
             * @param context faces context
             */
             public void processUpdates(FacesContext context) {
             try {
             super.processUpdates(context);
             } catch (Exception e) {
             handleException(context, e);
             context.responseComplete();
             }
             }
            
             /**
             * <p>Override to catch and handle exceptions in value change
             * listeners that might have occured in the process validations
             * phase.</p>
             *
             * @param context faces context
             */
             public void processValidators(FacesContext context) {
             try {
             super.processValidators(context);
             } catch (Exception e) {
             handleException(context, e);
             context.responseComplete();
             }
             }
            
            
             /**
             * <p>Handle the specified exception according to the strategy
             * defined by our current {@link ExceptionHandler}.</p>
             *
             * @param context FacesContext for the current request
             * @param exception Exception to be handled
             */
             private void handleException(FacesContext context, Exception exception) {
            
             if (context == null) {
             exception.printStackTrace(System.out);
             return;
             }
             ExceptionHandler handler = (ExceptionHandler)
             context.getApplication().getVariableResolver().resolveVariable
             (context, Constants.EXCEPTION_HANDLER);
             handler.handleException(exception);
            
             }
            }
            

            Changes from original code highlihted as bold.
            Also, register this component in the application faces-config.xml:
            <component>
             <component-type>javax.faces.ViewRoot</component-type>
             <component-class>foo.bar.AjaxShaleViewRoot</component-class>
             <component-extension>
             <component-family>javax.faces.ViewRoot</component-family>
             </component-extension>
            </component>

            Enjoy !

            • 3. Re: AjaxViewRoot implementation of javax.faces.ViewRoot
              Curtis Crabb Newbie

              Thanks for the quick response. It sounds like the solution you proposed will definitely work for me.

              However, I am still curious as to a solution that is not simply a "workaround"; I ask primarily out of a desire to more fully understand the jsf architecture (and how ajax4jsf works in that architecture).

              This seems like a design flaw of jsf if it encourages products to implement thier own ViewRoot and then not allow more than one ViewRoot implementation within an application. This requires us to create our own custom ViewRoot that combines the features of the ViewRoot from all products we use (at least the products which have a custom ViewRoot implementation); I would guess this is not always as easy a task as it is in this particular instance. In some cases, we might not even have the source code for some products.

              Would you agree with this statement? Or is there some concept that I don't understand? Might there be a good reference I can look at to better understand this?

              • 4. Re: AjaxViewRoot implementation of javax.faces.ViewRoot
                Alexander Smirnov Master

                Yes, yor are right.
                This not a very elegant solution, as far as JSF did't allow to create "components chain".
                This is a more elegant solution to place code into javax.faces.lifecycle.Lifecycle implementation. Unfortunatelly, not all necessary for AJAX processing methods are accessible from Lifecycle.
                On other hands, Lifecycle is a right place for a Shale code. Current solution can be hang by exceptions from PhaseListener's .