Coverage Report - org.apache.tapestry.contrib.link.FormLinkRenderer
 
Classes in this File Line Coverage Branch Coverage Complexity
FormLinkRenderer
0% 
0% 
6
 
 1  
 // Copyright 2004, 2005 The Apache Software Foundation
 2  
 //
 3  
 // Licensed under the Apache License, Version 2.0 (the "License");
 4  
 // you may not use this file except in compliance with the License.
 5  
 // You may obtain a copy of the License at
 6  
 //
 7  
 //     http://www.apache.org/licenses/LICENSE-2.0
 8  
 //
 9  
 // Unless required by applicable law or agreed to in writing, software
 10  
 // distributed under the License is distributed on an "AS IS" BASIS,
 11  
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 12  
 // See the License for the specific language governing permissions and
 13  
 // limitations under the License.
 14  
 
 15  
 package org.apache.tapestry.contrib.link;
 16  
 
 17  
 import org.apache.hivemind.ApplicationRuntimeException;
 18  
 import org.apache.tapestry.IMarkupWriter;
 19  
 import org.apache.tapestry.IRequestCycle;
 20  
 import org.apache.tapestry.PageRenderSupport;
 21  
 import org.apache.tapestry.Tapestry;
 22  
 import org.apache.tapestry.TapestryUtils;
 23  
 import org.apache.tapestry.components.ILinkComponent;
 24  
 import org.apache.tapestry.engine.ILink;
 25  
 import org.apache.tapestry.link.DefaultLinkRenderer;
 26  
 import org.apache.tapestry.link.ILinkRenderer;
 27  
 
 28  
 /**
 29  
  * A link renderer that ensures that the generated link uses POST instead of GET
 30  
  * request and is therefore no longer limited in size.
 31  
  * <p>
 32  
  * Theoretically, browsers should support very long URLs, but in practice they
 33  
  * often start behaving strangely if the URLs are more than 256 characters. This
 34  
  * renderer uses JavaScript to generate forms containing the requested link
 35  
  * parameters and then "post" them when the link is selected. As a result, the
 36  
  * data is sent to the server using a POST request with a very short URL and
 37  
  * there is no longer a limitation in the size of the parameters.
 38  
  * <p>
 39  
  * In short, simply add the following parameter to your <code>DirectLink</code>,
 40  
  * <code>ExternalLink</code>, or other such link components:
 41  
  * 
 42  
  * <pre>
 43  
  * renderer = &quot;ognl: @org.apache.tapestry.contrib.link.FormLinkRenderer@RENDERER&quot;
 44  
  * </pre>
 45  
  * 
 46  
  * and they will automatically start using POST rather than GET requests. Their
 47  
  * parameters will no longer be limited in size.
 48  
  * @author mb
 49  
  * @since 4.0
 50  
  */
 51  0
 public class FormLinkRenderer extends DefaultLinkRenderer
 52  
 {
 53  
 
 54  
     /**
 55  
      * A public singleton instance of the <code>FormLinkRenderer</code>.
 56  
      * <p>
 57  
      * Since the <code>FormLinkRenderer</code> is stateless, this instance can
 58  
      * serve all links within your application without interference.
 59  
      */
 60  0
     public static final ILinkRenderer RENDERER = new FormLinkRenderer();
 61  
 
 62  
     public void renderLink(IMarkupWriter writer, IRequestCycle cycle,
 63  
             ILinkComponent linkComponent)
 64  
     {
 65  0
         IMarkupWriter wrappedWriter = null;
 66  
 
 67  0
         if (cycle.getAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME) != null)
 68  0
             throw new ApplicationRuntimeException(Tapestry
 69  
                     .getMessage("AbstractLinkComponent.no-nesting"),
 70  
                     linkComponent, null, null);
 71  
 
 72  0
         cycle.setAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME,
 73  
                 linkComponent);
 74  
         
 75  0
         String formName = cycle.getUniqueId("LinkForm");
 76  
         
 77  0
         boolean hasBody = getHasBody();
 78  
 
 79  0
         boolean disabled = linkComponent.isDisabled();
 80  
 
 81  0
         if (!disabled && !cycle.isRewinding())
 82  
         {
 83  0
             ILink l = linkComponent.getLink(cycle);
 84  0
             String anchor = linkComponent.getAnchor();
 85  
             
 86  0
             PageRenderSupport prs = TapestryUtils.getPageRenderSupport(cycle, linkComponent);
 87  
             
 88  0
             String function = generateFormFunction(formName, l, anchor);
 89  0
             prs.addBodyScript(linkComponent, function);
 90  
             
 91  0
             if (hasBody)
 92  0
                 writer.begin(getElement());
 93  
             else 
 94  0
                 writer.beginEmpty(getElement());
 95  
             
 96  0
             writer.attribute(getUrlAttribute(), "javascript: document."
 97  
                     + formName + ".submit();");
 98  
             
 99  0
             beforeBodyRender(writer, cycle, linkComponent);
 100  
             
 101  
             // Allow the wrapped components a chance to render.
 102  
             // Along the way, they may interact with this component
 103  
             // and cause the name variable to get set.
 104  
 
 105  0
             wrappedWriter = writer.getNestedWriter();
 106  0
         }
 107  0
         else wrappedWriter = writer;
 108  
 
 109  0
         if (hasBody) linkComponent.renderBody(wrappedWriter, cycle);
 110  
 
 111  0
         if (!disabled && !cycle.isRewinding())
 112  
         {
 113  0
             afterBodyRender(writer, cycle, linkComponent);
 114  
 
 115  0
             linkComponent.renderAdditionalAttributes(writer, cycle);
 116  
 
 117  0
             if (hasBody)
 118  
             {
 119  0
                 wrappedWriter.close();
 120  
 
 121  
                 // Close the <element> tag
 122  
 
 123  0
                 writer.end();
 124  
             }
 125  0
             else writer.closeTag();
 126  
         }
 127  
 
 128  0
         cycle.removeAttribute(Tapestry.LINK_COMPONENT_ATTRIBUTE_NAME);
 129  
 
 130  0
     }
 131  
 
 132  
     private String generateFormFunction(String formName, ILink link,
 133  
             String anchor)
 134  
     {
 135  0
         String[] parameterNames = link.getParameterNames();
 136  
 
 137  0
         StringBuffer buf = new StringBuffer();
 138  0
         buf.append("function prepare" + formName + "() {\n");
 139  
 
 140  0
         buf.append("  var html = \"\";\n");
 141  0
         buf.append("  html += \"<div style='position: absolute'>\";\n");
 142  
 
 143  0
         String url = link.getURL(anchor, false);
 144  0
         buf.append("  html += \"<form name='" + formName
 145  
                 + "' method='post' action='" + url + "'>\";\n");
 146  
 
 147  0
         for(int i = 0; i < parameterNames.length; i++)
 148  
         {
 149  0
             String parameter = parameterNames[i];
 150  0
             String[] values = link.getParameterValues(parameter);
 151  0
             if (values != null) {               
 152  0
                 for (int j = 0; j < values.length; j++) {
 153  0
                     String value = values[j];
 154  0
                     buf.append("  html += \"<input type='hidden' name='" + parameter + "' value='" + value + "'/>\";\n");
 155  
                 }
 156  
             }
 157  
         }
 158  0
         buf.append("  html += \"<\" + \"/form>\";\n");
 159  0
         buf.append("  html += \"<\" + \"/div>\";\n");
 160  0
         buf.append("  document.write(html);\n");
 161  0
         buf.append("}\n");
 162  
 
 163  0
         buf.append("prepare" + formName + "();\n\n");
 164  
 
 165  0
         return buf.toString();
 166  
     }
 167  
 
 168  
 }