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