2009/05/20 - Apache Shale has been retired.

For more information, please explore the Attic.

Coverage Report - org.apache.shale.tiles.TilesViewHandler
 
Classes in this File Line Coverage Branch Coverage Complexity
TilesViewHandler
0%
0/86
0%
0/7
2
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to you under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 
 18  
 package org.apache.shale.tiles;
 19  
 
 20  
 import java.io.IOException;
 21  
 import java.text.MessageFormat;
 22  
 import java.util.Locale;
 23  
 import java.util.MissingResourceException;
 24  
 import java.util.ResourceBundle;
 25  
 
 26  
 import javax.faces.FacesException;
 27  
 import javax.faces.application.ViewHandler;
 28  
 import javax.faces.component.UIViewRoot;
 29  
 import javax.faces.context.ExternalContext;
 30  
 import javax.faces.context.FacesContext;
 31  
 
 32  
 import org.apache.commons.logging.Log;
 33  
 import org.apache.commons.logging.LogFactory;
 34  
 import org.apache.tiles.ComponentContext;
 35  
 import org.apache.tiles.ComponentDefinition;
 36  
 import org.apache.tiles.DefinitionsFactoryException;
 37  
 import org.apache.tiles.NoSuchDefinitionException;
 38  
 import org.apache.tiles.TilesRequestContext;
 39  
 import org.apache.tiles.TilesUtil;
 40  
 import org.apache.tiles.context.BasicTilesContextFactory;
 41  
 
 42  
 /**
 43  
  * This view handler strips the suffix off of the view ID and looks
 44  
  * for a tile whose name matches the resulting string. For example, if the
 45  
  * view ID is /tiles/test.jsp, this view handler will look for a tile named
 46  
  * /tiles/test. If the tile is found, it is rendered; otherwise, this view handler 
 47  
  * delegates to the default JSF view handler.
 48  
  * <p/>
 49  
  * To render a tile, this view handler first locates the tile by name. Then it
 50  
  * creates or accesses the Tile Context, and stores the tile's attributes
 51  
  * in the context. Finally, it dispatches the request to the tile's layout
 52  
  * by calling JSF's <code>ExternalContext.dispatch()</code>. Layouts typically
 53  
  * contain &lt;tiles:insert&gt; tags that include dynamic content.
 54  
  * <p/>
 55  
  * If the request does not reference a tile, this view handler delegates
 56  
  * view rendering to the default view handler. That means that URLs like this:
 57  
  * <code>http://localhost:8080/example/index.faces</code> will work as 
 58  
  * expected.
 59  
  *<p/>
 60  
  * Most of the methods in this class simply delegate to the default view
 61  
  * handler, which JSF passes to this view handler's constructor. The only
 62  
  * method that has a meaningful implementation is <code>void 
 63  
  * renderView(FacesContext, UIViewRoot)</code>, which renders the current
 64  
  * view in accordance with the algorithm discussed above.
 65  
  *
 66  
  * <strong>Note:</strong> This Tiles view handler is tied to the standalone 
 67  
  * version of Tiles, which resides in the Struts sandbox. This view handler
 68  
  * will not work with Struts Tiles.
 69  
  */
 70  
 public class TilesViewHandler extends ViewHandler {
 71  
 
 72  
 
 73  
    // ------------------------------------------------------------- Constructor
 74  
 
 75  
 
 76  
    /**
 77  
     * <p>Stores the reference to the default view handler for later use.</p>
 78  
     * 
 79  
     * @param defaultViewHandler The default view handler
 80  
     */
 81  0
    public TilesViewHandler(ViewHandler defaultViewHandler) {
 82  0
       this.defaultViewHandler = defaultViewHandler;
 83  0
    }
 84  
 
 85  
 
 86  
    // -------------------------------------------------------- Static Variables
 87  
 
 88  
     
 89  
    /**
 90  
     * <p><code>MessageFormat</code> used to perform parameter substitution.</p>
 91  
     */
 92  0
    private MessageFormat format = new MessageFormat("");
 93  
 
 94  
 
 95  
    /**
 96  
     * <p>Log instance for this class.</p>
 97  
     */
 98  0
    private static final Log log = LogFactory.getLog(
 99  0
                                             TilesViewHandler.class.getName());
 100  
    /**
 101  
     * <p>Message resources for this class.</p>
 102  
     */
 103  0
    private static ResourceBundle bundle =
 104  
       ResourceBundle.getBundle("org.apache.shale.tiles.Bundle",
 105  
                                Locale.getDefault(),
 106  
                                TilesViewHandler.class.getClassLoader());
 107  
 
 108  
     /**
 109  
      * <p>The default JSF view handler.</p>
 110  
      */
 111  0
    private ViewHandler defaultViewHandler = null;
 112  
 
 113  
 
 114  
    // ----------------------------------------------------- ViewHandler Methods
 115  
 
 116  
 
 117  
    /**
 118  
     * <p>Render a view according to the algorithm described in this class's
 119  
     * description: Based on the view Id of the <code>viewToRender</code>, 
 120  
     * this method either renders a tile or delegates rendering to the default 
 121  
     * view handler, which takes care of business as usual.</p>
 122  
     *
 123  
     * @param facesContext The faces context object for this request
 124  
     * @param viewToRender The view that we're rendering
 125  
     */
 126  
    public void renderView(FacesContext facesContext, UIViewRoot viewToRender) 
 127  
                                         throws IOException, FacesException {
 128  0
       String viewId = viewToRender.getViewId();
 129  0
       String tileName = getTileName(viewId);
 130  0
       ComponentDefinition tile = getTile(tileName);
 131  
 
 132  0
       if (log.isDebugEnabled()) {
 133  0
          String message = null;
 134  
          try {
 135  0
              message = bundle.getString("tiles.renderingView");
 136  0
          } catch (MissingResourceException e) {
 137  0
              message = "Rendering view {0}, looking for tile {1}";
 138  0
          }
 139  0
          synchronized(format) {
 140  0
             format.applyPattern(message);
 141  0
             message = format.format(new Object[] { viewId, tileName });
 142  0
          }
 143  0
          log.debug(message);
 144  
       }
 145  
 
 146  0
       if (tile != null) {
 147  0
          if (log.isDebugEnabled()) {
 148  0
             String message = null;
 149  
             try {
 150  0
                 message = bundle.getString("tiles.dispatchingToTile");
 151  0
             } catch (MissingResourceException e) {
 152  0
                 message = "Dispatching to tile {0}";
 153  0
             }
 154  0
             synchronized(format) {
 155  0
                format.applyPattern(message);
 156  0
                message = format.format(new Object[] { tileName });
 157  0
             }
 158  0
             log.debug(message);
 159  
          }
 160  0
          dispatchToTile(facesContext.getExternalContext(), tile);
 161  0
       }
 162  
       else {
 163  0
          if (log.isDebugEnabled()) {
 164  0
             String message = null;
 165  
             try {
 166  0
                 message = bundle.getString("tiles.dispatchingToViewHandler");
 167  0
             } catch (MissingResourceException e) {
 168  0
                 message = "Dispatching {0} to the default view handler";
 169  0
             }
 170  0
             synchronized(format) {
 171  0
                format.applyPattern(message);
 172  0
                message = format.format(new Object[] { viewId });
 173  0
             }
 174  0
             log.debug(message);
 175  
          }
 176  0
          defaultViewHandler.renderView(facesContext, viewToRender);
 177  
       }
 178  0
    }
 179  
 
 180  
    /**
 181  
     * <p>Pass through to the default view handler.</p>
 182  
     * 
 183  
     */
 184  
    public UIViewRoot createView(FacesContext context, String viewId) {
 185  0
       return defaultViewHandler.createView(context, viewId);
 186  
    }
 187  
 
 188  
 
 189  
    /**
 190  
     * <p>Pass through to the default view handler.</p>
 191  
     * 
 192  
     */
 193  
    public Locale calculateLocale(FacesContext context) {
 194  0
       return defaultViewHandler.calculateLocale(context);
 195  
    }
 196  
     
 197  
 
 198  
    /**
 199  
     * <p>Pass through to the default view handler.</p>
 200  
     * 
 201  
     */
 202  
    public String calculateRenderKitId(FacesContext context) {
 203  0
       return defaultViewHandler.calculateRenderKitId(context);
 204  
    }
 205  
     
 206  
 
 207  
    /**
 208  
     * <p>Pass through to the default view handler.</p>
 209  
     * 
 210  
     */
 211  
    public String getActionURL(FacesContext context, String viewId) {
 212  0
       return defaultViewHandler.getActionURL(context, viewId);
 213  
    }
 214  
     
 215  
 
 216  
    /**
 217  
     * <p>Pass through to the default view handler.</p>
 218  
     * 
 219  
     */
 220  
    public String getResourceURL(FacesContext context, String path) {
 221  0
       return defaultViewHandler.getResourceURL(context, path);
 222  
    }
 223  
     
 224  
 
 225  
    /**
 226  
     * <p>Pass through to the default view handler.</p>
 227  
     * 
 228  
     */
 229  
    public UIViewRoot restoreView(FacesContext context, String viewId) {
 230  0
       return defaultViewHandler.restoreView(context, viewId);
 231  
    }
 232  
     
 233  
 
 234  
    /**
 235  
     * <p>Pass through to the default view handler.</p>
 236  
     * 
 237  
     */
 238  
    public void writeState(FacesContext context) throws IOException {
 239  0
       defaultViewHandler.writeState(context);
 240  0
    }
 241  
 
 242  
 
 243  
    // --------------------------------------------------------- Private Methods
 244  
 
 245  
 
 246  
    /**
 247  
     * <p>Looks up a tile, given a name. If the tile does not exist, and the
 248  
     * <code>name</code> begins with a slash ('/'), look for a tile
 249  
     * without the slash. If no tile is found, return <code>null</code>.</p>
 250  
     * 
 251  
     * @param name The tile to lookup
 252  
     */
 253  
    private ComponentDefinition getTile(String name) {
 254  0
       if (name == null) 
 255  0
          return null;
 256  
 
 257  0
       ExternalContext externalContext = FacesContext.getCurrentInstance()
 258  
                                                     .getExternalContext();
 259  0
       Object request = externalContext.getRequest();
 260  0
       Object context = externalContext.getContext();
 261  0
       Object response = externalContext.getResponse();
 262  0
       ComponentDefinition tile = null;
 263  
       try {
 264  0
         TilesRequestContext tilesContext =
 265  
             new BasicTilesContextFactory().createRequestContext(context,
 266  
             request, response);
 267  0
         tile = TilesUtil.getDefinition(name, tilesContext);
 268  0
       } catch (NoSuchDefinitionException nsex) {
 269  0
           log.error("Couldn't find Tiles definition.", nsex);
 270  0
       } catch (DefinitionsFactoryException dex) {
 271  0
           log.error("Tiles error", dex);
 272  0
       }
 273  0
       return tile;
 274  
 
 275  
    }
 276  
 
 277  
    /**
 278  
     * <p>Given a view ID, returns the name of the corresponding tile. For 
 279  
     * example, for a view ID of /tiles/example/main.jsp, the tile name 
 280  
     * returned by this method would be /tiles/example/main.</p>
 281  
     * 
 282  
     * @param viewId The view ID
 283  
     */
 284  
    private String getTileName(String viewId) {
 285  0
       int suffixIndex = viewId.lastIndexOf('.');
 286  0
       return suffixIndex != -1 ? viewId.substring(0, suffixIndex)
 287  
                                : viewId;
 288  
    }
 289  
 
 290  
    /**
 291  
     * <p>Dispatches to a tile's layout. Layouts typically contain
 292  
     * &lt;tiles:insert&gt; tags that include content, so dispatching
 293  
     * to the tile's layout will automatically build the tile.</p>
 294  
     * <p>
 295  
     * Before dispatching to the tile, this method sets up the Tile
 296  
     * context.</p>
 297  
     * 
 298  
     * @param externalContext The JSF external context
 299  
     * @param tile The tile definition
 300  
     */
 301  
    private void dispatchToTile(ExternalContext externalContext,
 302  
                                ComponentDefinition tile) 
 303  
                                throws java.io.IOException {
 304  0
       Object request = externalContext.getRequest();
 305  0
       Object context = externalContext.getContext();
 306  0
       Object response = externalContext.getResponse();
 307  0
       TilesRequestContext tilesContext =
 308  
           new BasicTilesContextFactory().createRequestContext(context,
 309  
           request, response);
 310  0
       ComponentContext tileContext = ComponentContext.getContext(tilesContext);
 311  0
       if (tileContext == null) {
 312  0
          tileContext = new ComponentContext(tile.getAttributes());
 313  0
          ComponentContext.setContext(tileContext, tilesContext);
 314  0
       }
 315  
       else
 316  0
          tileContext.addMissing(tile.getAttributes());
 317  
    
 318  
       // dispatch to the tile's layout
 319  0
       externalContext.dispatch(tile.getPath());
 320  0
    }
 321  
 }