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