Coverage Report - org.apache.tapestry.services.impl.PrototypeResponseBuilder
 
Classes in this File Line Coverage Branch Coverage Complexity
PrototypeResponseBuilder
20% 
32% 
1.786
 
 1  
 package org.apache.tapestry.services.impl;
 2  
 
 3  
 import org.apache.hivemind.Resource;
 4  
 import org.apache.hivemind.util.Defense;
 5  
 import org.apache.tapestry.*;
 6  
 import org.apache.tapestry.asset.AssetFactory;
 7  
 import org.apache.tapestry.engine.NullWriter;
 8  
 import org.apache.tapestry.markup.MarkupWriterSource;
 9  
 import org.apache.tapestry.markup.NestedMarkupWriterImpl;
 10  
 import org.apache.tapestry.services.RequestLocaleManager;
 11  
 import org.apache.tapestry.services.ResponseBuilder;
 12  
 import org.apache.tapestry.services.ServiceConstants;
 13  
 import org.apache.tapestry.util.ContentType;
 14  
 import org.apache.tapestry.util.PageRenderSupportImpl;
 15  
 import org.apache.tapestry.web.WebResponse;
 16  
 
 17  
 import java.io.IOException;
 18  
 import java.io.PrintWriter;
 19  
 import java.util.*;
 20  
 
 21  
 /**
 22  
  * Implementation of response builder for prototype client side library initiated XHR requests.
 23  
  * 
 24  
  */
 25  
 public class PrototypeResponseBuilder implements ResponseBuilder {
 26  
 
 27  
     public static final String CONTENT_TYPE = "text/html";
 28  
 
 29  
     private final AssetFactory _assetFactory;
 30  
 
 31  
     private final String _namespace;
 32  
 
 33  
     private PageRenderSupportImpl _prs;
 34  
 
 35  
     // used to create IMarkupWriter
 36  
     private RequestLocaleManager _localeManager;
 37  
     private MarkupWriterSource _markupWriterSource;
 38  
     private WebResponse _response;
 39  
 
 40  
     // our response writer
 41  
     private IMarkupWriter _writer;
 42  
 
 43  
     // Parts that will be updated.
 44  2
     private List _parts = new ArrayList();
 45  
 
 46  
     // Map of specialized writers, like scripts
 47  
 
 48  2
     private Map _writers = new HashMap();
 49  
     private IRequestCycle _cycle;
 50  
 
 51  
     /**
 52  
      * Used for unit testing only.
 53  
      *
 54  
      * @param cycle Request.
 55  
      * @param writer Markup writer.
 56  
      * @param parts Update parts list.
 57  
      */
 58  
     public PrototypeResponseBuilder(IRequestCycle cycle, IMarkupWriter writer, List parts)
 59  2
     {
 60  2
         _cycle = cycle;
 61  2
         _writer = writer;
 62  
         
 63  2
         if (parts != null)
 64  1
             _parts.addAll(parts);
 65  
 
 66  2
         _assetFactory = null;
 67  2
         _namespace = null;
 68  2
     }
 69  
 
 70  
     /**
 71  
      * Creates a new response builder with the required services it needs
 72  
      * to render the response when {@link #renderResponse(IRequestCycle)} is called.
 73  
      * 
 74  
      * @param cycle
 75  
      *          Associated request.
 76  
      * @param localeManager
 77  
      *          Locale manager to use for response.
 78  
      * @param markupWriterSource
 79  
      *          Creates necessary {@link IMarkupWriter} instances.
 80  
      * @param webResponse
 81  
      *          The http response.
 82  
      * @param assetFactory
 83  
      *          Asset manager for script / other resource inclusion.
 84  
      * @param namespace
 85  
      *          Javascript namespace value - used in portlets.
 86  
      */
 87  
     public PrototypeResponseBuilder(IRequestCycle cycle,
 88  
             RequestLocaleManager localeManager,
 89  
             MarkupWriterSource markupWriterSource,
 90  
             WebResponse webResponse,
 91  
             AssetFactory assetFactory, String namespace)
 92  0
     {
 93  0
         Defense.notNull(cycle, "cycle");
 94  0
         Defense.notNull(assetFactory, "assetService");
 95  
 
 96  0
         _cycle = cycle;
 97  0
         _localeManager = localeManager;
 98  0
         _markupWriterSource = markupWriterSource;
 99  0
         _response = webResponse;
 100  
 
 101  
         // Used by PageRenderSupport
 102  
 
 103  0
         _assetFactory = assetFactory;
 104  0
         _namespace = namespace;
 105  0
     }
 106  
 
 107  
     /**
 108  
      *
 109  
      * {@inheritDoc}
 110  
      */
 111  
     public boolean isDynamic()
 112  
     {
 113  0
         return true;
 114  
     }
 115  
 
 116  
     /**
 117  
      * {@inheritDoc}
 118  
      */
 119  
     public void renderResponse(IRequestCycle cycle)
 120  
         throws IOException
 121  
     {
 122  0
         _localeManager.persistLocale();
 123  
 
 124  0
         ContentType contentType = new ContentType(CONTENT_TYPE + ";charset=" + cycle.getInfrastructure().getOutputEncoding());
 125  
 
 126  0
         String encoding = contentType.getParameter(ENCODING_KEY);
 127  
 
 128  0
         if (encoding == null)
 129  
         {
 130  0
             encoding = cycle.getEngine().getOutputEncoding();
 131  
 
 132  0
             contentType.setParameter(ENCODING_KEY, encoding);
 133  
         }
 134  
 
 135  0
         if (_writer == null) {
 136  
 
 137  0
             parseParameters(cycle);
 138  
 
 139  0
             PrintWriter printWriter = _response.getPrintWriter(contentType);
 140  
 
 141  0
             _writer = _markupWriterSource.newMarkupWriter(printWriter, contentType);
 142  
         }
 143  
 
 144  
         // render response
 145  
 
 146  0
         _prs = new PageRenderSupportImpl(_assetFactory, _namespace, cycle.getPage().getLocation(), this);
 147  
 
 148  0
         TapestryUtils.storePageRenderSupport(cycle, _prs);
 149  
 
 150  0
         cycle.renderPage(this);
 151  
 
 152  0
         TapestryUtils.removePageRenderSupport(cycle);
 153  
 
 154  0
         endResponse();
 155  
 
 156  0
         _writer.close();
 157  0
     }
 158  
 
 159  
     public void flush()
 160  
     throws IOException
 161  
     {
 162  0
         _writer.flush();
 163  0
     }
 164  
 
 165  
     /**
 166  
      * {@inheritDoc}
 167  
      */
 168  
     public void updateComponent(String id)
 169  
     {
 170  0
         if (!_parts.contains(id))
 171  0
             _parts.add(id);
 172  0
     }
 173  
 
 174  
     /**
 175  
      * {@inheritDoc}
 176  
      */
 177  
     public IMarkupWriter getWriter()
 178  
     {
 179  2
         return _writer;
 180  
     }
 181  
 
 182  
     void setWriter(IMarkupWriter writer)
 183  
     {
 184  0
         _writer = writer;
 185  0
     }
 186  
 
 187  
     /**
 188  
      * {@inheritDoc}
 189  
      */
 190  
     public boolean isBodyScriptAllowed(IComponent target)
 191  
     {
 192  0
         if (target != null
 193  2
                 && IPage.class.isInstance(target)
 194  
                 || (IForm.class.isInstance(target)
 195  
                 && ((IForm)target).isFormFieldUpdating()))
 196  0
             return true;
 197  
 
 198  0
         return contains(target);
 199  
     }
 200  
 
 201  
     /**
 202  
      * {@inheritDoc}
 203  
      */
 204  
     public boolean isExternalScriptAllowed(IComponent target)
 205  
     {
 206  0
         if (target != null
 207  
                 && IPage.class.isInstance(target)
 208  
                 || (IForm.class.isInstance(target)
 209  
                 && ((IForm)target).isFormFieldUpdating()))
 210  0
             return true;
 211  
 
 212  0
         return contains(target);
 213  
     }
 214  
 
 215  
     /**
 216  
      * {@inheritDoc}
 217  
      */
 218  
     public boolean isInitializationScriptAllowed(IComponent target)
 219  
     {
 220  0
         if (target != null
 221  
                 && IPage.class.isInstance(target)
 222  
                 || (IForm.class.isInstance(target)
 223  
                 && ((IForm)target).isFormFieldUpdating()))
 224  0
             return true;
 225  
 
 226  0
         return contains(target);
 227  
     }
 228  
 
 229  
     /**
 230  
      * {@inheritDoc}
 231  
      */
 232  
     public boolean isImageInitializationAllowed(IComponent target)
 233  
     {
 234  0
         if (target != null
 235  
                 && IPage.class.isInstance(target)
 236  
                 || (IForm.class.isInstance(target)
 237  
                 && ((IForm)target).isFormFieldUpdating()))
 238  0
             return true;
 239  
 
 240  0
         return contains(target);
 241  
     }
 242  
 
 243  
     /**
 244  
      * {@inheritDoc}
 245  
      */
 246  
     public String getPreloadedImageReference(IComponent target, IAsset source)
 247  
     {
 248  0
         return _prs.getPreloadedImageReference(target, source);
 249  
     }
 250  
 
 251  
     /**
 252  
      * {@inheritDoc}
 253  
      */
 254  
     public String getPreloadedImageReference(IComponent target, String url)
 255  
     {
 256  0
         return _prs.getPreloadedImageReference(target, url);
 257  
     }
 258  
 
 259  
     /**
 260  
      * {@inheritDoc}
 261  
      */
 262  
     public String getPreloadedImageReference(String url)
 263  
     {
 264  0
         return _prs.getPreloadedImageReference(url);
 265  
     }
 266  
 
 267  
     /**
 268  
      * {@inheritDoc}
 269  
      */
 270  
     public void addBodyScript(IComponent target, String script)
 271  
     {
 272  0
         _prs.addBodyScript(target, script);
 273  0
     }
 274  
 
 275  
     /**
 276  
      * {@inheritDoc}
 277  
      */
 278  
     public void addBodyScript(String script)
 279  
     {
 280  0
         _prs.addBodyScript(script);
 281  0
     }
 282  
 
 283  
     /**
 284  
      * {@inheritDoc}
 285  
      */
 286  
     public void addExternalScript(IComponent target, Resource resource)
 287  
     {
 288  0
         _prs.addExternalScript(target, resource);
 289  0
     }
 290  
 
 291  
     /**
 292  
      * {@inheritDoc}
 293  
      */
 294  
     public void addExternalScript(Resource resource)
 295  
     {
 296  0
         _prs.addExternalScript(resource);
 297  0
     }
 298  
 
 299  
     /**
 300  
      * {@inheritDoc}
 301  
      */
 302  
     public void addInitializationScript(IComponent target, String script)
 303  
     {
 304  0
         _prs.addInitializationScript(target, script);
 305  0
     }
 306  
 
 307  
     /**
 308  
      * {@inheritDoc}
 309  
      */
 310  
     public void addInitializationScript(String script)
 311  
     {
 312  0
         _prs.addInitializationScript(script);
 313  0
     }
 314  
 
 315  
     /**
 316  
      * {@inheritDoc}
 317  
      */
 318  
     public String getUniqueString(String baseValue)
 319  
     {
 320  0
         return _prs.getUniqueString(baseValue);
 321  
     }
 322  
 
 323  
     /**
 324  
      * {@inheritDoc}
 325  
      */
 326  
     public void writeBodyScript(IMarkupWriter writer, IRequestCycle cycle)
 327  
     {
 328  0
         _prs.writeBodyScript(writer, cycle);
 329  0
     }
 330  
 
 331  
     /**
 332  
      * {@inheritDoc}
 333  
      */
 334  
     public void writeInitializationScript(IMarkupWriter writer)
 335  
     {
 336  0
         _prs.writeInitializationScript(writer);
 337  0
     }
 338  
 
 339  
     /**
 340  
      * {@inheritDoc}
 341  
      */
 342  
     public void beginBodyScript(IMarkupWriter normalWriter, IRequestCycle cycle)
 343  
     {
 344  0
         _writer.begin("script");
 345  0
         _writer.printRaw("\n//<![CDATA[\n");
 346  0
     }
 347  
 
 348  
     /**
 349  
      * {@inheritDoc}
 350  
      */
 351  
     public void endBodyScript(IMarkupWriter normalWriter, IRequestCycle cycle)
 352  
     {
 353  0
         _writer.printRaw("\n//]]>\n");
 354  0
         _writer.end();
 355  0
     }
 356  
 
 357  
     /**
 358  
      * {@inheritDoc}
 359  
      */
 360  
     public void writeBodyScript(IMarkupWriter normalWriter, String script, IRequestCycle cycle)
 361  
     {
 362  0
         _writer.printRaw(script);
 363  0
     }
 364  
 
 365  
     /**
 366  
      * {@inheritDoc}
 367  
      */
 368  
     public void writeExternalScript(IMarkupWriter normalWriter, String url, IRequestCycle cycle)
 369  
     {
 370  0
         _writer.begin("script");
 371  0
         _writer.attribute("type", "text/javascript");
 372  0
         _writer.attribute("src", url);
 373  0
         _writer.end();
 374  0
     }
 375  
 
 376  
     /**
 377  
      * {@inheritDoc}
 378  
      */
 379  
     public void writeImageInitializations(IMarkupWriter normalWriter, String script, String preloadName, IRequestCycle cycle)
 380  
     {
 381  0
     }
 382  
 
 383  
     /**
 384  
      * {@inheritDoc}
 385  
      */
 386  
     public void writeInitializationScript(IMarkupWriter normalWriter, String script)
 387  
     {
 388  0
         _writer.begin("script");
 389  
 
 390  
         // return is in XML so must escape any potentially non-xml compliant content
 391  0
         _writer.printRaw("\n//<![CDATA[\n");
 392  0
         _writer.printRaw(script);
 393  0
         _writer.printRaw("\n//]]>\n");
 394  0
         _writer.end();
 395  0
     }
 396  
 
 397  
     public void addStatus(IMarkupWriter normalWriter, String text)
 398  
     {
 399  0
         throw new UnsupportedOperationException("Can't return a status response with prototype based requests.");
 400  
     }
 401  
 
 402  
     public void addStatusMessage(IMarkupWriter normalWriter, String category, String text)
 403  
     {
 404  0
         throw new UnsupportedOperationException("Can't return a status response with prototype based requests.");
 405  
     }
 406  
     
 407  
     /**
 408  
      * {@inheritDoc}
 409  
      */
 410  
     public void render(IMarkupWriter writer, IRender render, IRequestCycle cycle)
 411  
     {
 412  
         // must be a valid writer already
 413  
 
 414  3
         if (NestedMarkupWriterImpl.class.isInstance(writer)) {
 415  0
             render.render(writer, cycle);
 416  0
             return;
 417  
         }
 418  
 
 419  3
         if (IComponent.class.isInstance(render)
 420  
             && contains((IComponent)render, ((IComponent)render).peekClientId()))
 421  
         {
 422  1
             render.render(getComponentWriter( ((IComponent)render).peekClientId() ), cycle);
 423  1
             return;
 424  
         }
 425  
 
 426  
         // Nothing else found, throw out response
 427  
 
 428  2
         render.render(NullWriter.getSharedInstance(), cycle);
 429  2
     }
 430  
 
 431  
     IMarkupWriter getComponentWriter(String id)
 432  
     {
 433  1
         return getWriter(id, ELEMENT_TYPE);
 434  
     }
 435  
 
 436  
     /**
 437  
      *
 438  
      * {@inheritDoc}
 439  
      */
 440  
     public IMarkupWriter getWriter(String id, String type)
 441  
     {
 442  1
         Defense.notNull(id, "id can't be null");
 443  
         
 444  1
         IMarkupWriter w = (IMarkupWriter)_writers.get(id);
 445  1
         if (w != null)
 446  0
             return w;
 447  
         
 448  1
         IMarkupWriter nestedWriter = _writer.getNestedWriter();
 449  1
         _writers.put(id, nestedWriter);
 450  
 
 451  1
         return nestedWriter;
 452  
     }
 453  
 
 454  
     void beginResponse()
 455  
     {
 456  0
     }
 457  
 
 458  
     /**
 459  
      * Invoked to clear out tempoary partial writer buffers before rendering exception
 460  
      * page.
 461  
      */
 462  
     void clearPartialWriters()
 463  
     {
 464  0
         _writers.clear();
 465  0
     }
 466  
 
 467  
     /**
 468  
      * Called after the entire response has been captured. Causes
 469  
      * the writer buffer output captured to be segmented and written
 470  
      * out to the right response elements for the client libraries to parse.
 471  
      */
 472  
     void endResponse()
 473  
     {
 474  0
         Iterator keys = _writers.keySet().iterator();
 475  
 
 476  0
         while (keys.hasNext()) {
 477  
 
 478  0
             String key = (String)keys.next();
 479  0
             NestedMarkupWriter nw = (NestedMarkupWriter)_writers.get(key);
 480  
             
 481  0
             nw.close();
 482  0
         }
 483  
         
 484  0
         _writer.flush();
 485  0
     }
 486  
 
 487  
     /**
 488  
      * Grabs the incoming parameters needed for json responses, most notable the
 489  
      * {@link ServiceConstants#UPDATE_PARTS} parameter.
 490  
      *
 491  
      * @param cycle
 492  
      *            The request cycle to parse from
 493  
      */
 494  
     void parseParameters(IRequestCycle cycle)
 495  
     {
 496  0
         Object[] updateParts = cycle.getParameters(ServiceConstants.UPDATE_PARTS);
 497  
 
 498  0
         if (updateParts == null)
 499  0
             return;
 500  
 
 501  0
         for(int i = 0; i < updateParts.length; i++)
 502  
         {
 503  0
             _parts.add(updateParts[i].toString());
 504  
         }
 505  0
     }
 506  
 
 507  
     /**
 508  
      * Determines if the specified component is contained in the
 509  
      * responses requested update parts.
 510  
      * @param target
 511  
      *          The component to check for.
 512  
      * @return True if the request should capture the components output.
 513  
      */
 514  
     public boolean contains(IComponent target)
 515  
     {
 516  1
         if (target == null)
 517  0
             return false;
 518  
 
 519  1
         String id = target.getClientId();
 520  
 
 521  1
         return contains(target, id);
 522  
     }
 523  
 
 524  
     boolean contains(IComponent target, String id)
 525  
     {
 526  2
         if (_parts.contains(id))
 527  2
             return true;
 528  
 
 529  0
         Iterator it = _cycle.renderStackIterator();
 530  0
         while (it.hasNext()) {
 531  
 
 532  0
             IComponent comp = (IComponent)it.next();
 533  0
             String compId = comp.getClientId();
 534  
 
 535  0
             if (comp != target && _parts.contains(compId))
 536  0
                 return true;
 537  0
         }
 538  
 
 539  0
         return false;
 540  
     }
 541  
 
 542  
     /**
 543  
      * {@inheritDoc}
 544  
      */
 545  
     public boolean explicitlyContains(IComponent target)
 546  
     {
 547  0
         if (target == null)
 548  0
             return false;
 549  
 
 550  0
         return _parts.contains(target.getId());
 551  
     }
 552  
 }