| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| package org.apache.click.control; |
| |
| import org.apache.click.Context; |
| import org.apache.click.util.ClickUtils; |
| import org.apache.click.util.HtmlStringBuffer; |
| |
| import org.apache.commons.lang.StringUtils; |
| |
| /** |
| * Provides a Action Link control: <a href=""></a>. |
| * |
| * <table class='htmlHeader' cellspacing='6'> |
| * <tr><td> |
| * <a href='' title='ActionLink Control'>Action Link</a> |
| * </td></tr> |
| * </table> |
| * |
| * This control can render the "href" URL attribute using |
| * {@link #getHref()}, or the entire ActionLink anchor tag using |
| * {@link #toString()}. |
| * <p/> |
| * ActionLink support invoking control listeners. |
| * |
| * <h3>ActionLink Example</h3> |
| * |
| * An example of using ActionLink to call a logout method is illustrated below: |
| * |
| * <pre class="codeJava"> |
| * <span class="kw">public class</span> MyPage <span class="kw">extends</span> Page { |
| * |
| * <span class="kw">public</span> MyPage() { |
| * ActionLink link = <span class="kw">new</span> ActionLink(<span class="st">"logoutLink"</span>); |
| * link.setListener(<span class="kw">this</span>, <span class="st">"onLogoutClick"</span>); |
| * addControl(link); |
| * } |
| * |
| * <span class="kw">public boolean</span> onLogoutClick() { |
| * <span class="kw">if</span> (getContext().hasSession()) { |
| * getContext().getSession().invalidate(); |
| * } |
| * setRedirect(LogoutPage.<span class="kw">class</span>); |
| * |
| * <span class="kw">return false</span>; |
| * } |
| * } </pre> |
| * |
| * The corresponding template code is below. Note href is evaluated by Velocity |
| * to {@link #getHref()}: |
| * |
| * <pre class="codeHtml"> |
| * <a href="<span class="blue">$logoutLink</span>.href" title="Click to Logout">Logout</a> </pre> |
| * |
| * ActionLink can also support a value parameter which is accessible |
| * using {@link #getValue()}. |
| * <p/> |
| * For example a products table could include rows |
| * of products, each with a get product details ActionLink and add product |
| * ActionLink. The ActionLinks include the product's id as a parameter to |
| * the {@link #getHref(Object)} method, which is then available when the |
| * control is processed: |
| * |
| * <pre class="codeHtml"> |
| * <table> |
| * <span class="red">#foreach</span> (<span class="blue">$product</span> <span class="red">in</span> <span class="blue">$productList</span>) |
| * <tr> |
| * <td> |
| * $product.name |
| * </td> |
| * <td> |
| * <a href="<span class="blue">$detailsLink</span>.getHref(<span class="blue">$product</span>.id)" title="Get product information">Details</a> |
| * </td> |
| * <td> |
| * <a href="<span class="blue">$addLink</span>.getHref(<span class="blue">$product</span>.id)" title="Add to basket">Add</a> |
| * </td> |
| * </tr> |
| * <span class="red">#end</span> |
| * </table> </pre> |
| * |
| * The corresponding Page class for this template is: |
| * |
| * <pre class="codeJava"> |
| * <span class="kw">public class</span> ProductsPage <span class="kw">extends</span> Page { |
| * |
| * <span class="kw">public</span> ActionLink addLink = <span class="kw">new</span> ActionLink(<span class="st">"addLink"</span>, <span class="kw">this</span>, <span class="st">"onAddClick"</span>); |
| * <span class="kw">public</span> ActionLink detailsLink = <span class="kw">new</span> ActionLink(<span class="st">"detailsLink"</span>, <span class="kw">this</span>, <span class="st">"onDetailsClick"</span>); |
| * <span class="kw">public</span> List productList; |
| * |
| * <span class="kw">public boolean</span> onAddClick() { |
| * <span class="cm">// Get the product clicked on by the user</span> |
| * Integer productId = addLink.getValueInteger(); |
| * Product product = getProductService().getProduct(productId); |
| * |
| * <span class="cm">// Add product to basket</span> |
| * List basket = (List) getContext().getSessionAttribute(<span class="st">"basket"</span>); |
| * basket.add(product); |
| * getContext().setSessionAttribute(<span class="st">"basket"</span>, basket); |
| * |
| * <span class="kw">return true</span>; |
| * } |
| * |
| * <span class="kw">public boolean</span> onDetailsClick() { |
| * <span class="cm">// Get the product clicked on by the user</span> |
| * Integer productId = detailsLink.getValueInteger(); |
| * Product product = getProductService().getProduct(productId); |
| * |
| * <span class="cm">// Store the product in the request and display in the details page</span> |
| * getContext().setRequestAttribute(<span class="st">"product"</span>, product); |
| * setForward(ProductDetailsPage.<span class="kw">class</span>); |
| * |
| * <span class="kw">return false</span>; |
| * } |
| * |
| * <span class="kw">public void</span> onRender() { |
| * <span class="cm">// Display the list of available products</span> |
| * productList = getProductService().getProducts(); |
| * } |
| * } </pre> |
| * |
| * See also the W3C HTML reference: |
| * <a class="external" target="_blank" title="W3C HTML 4.01 Specification" |
| * href="http://www.w3.org/TR/html401/struct/links.html#h-12.2">A Links</a> |
| * |
| * @see AbstractLink |
| * @see Submit |
| */ |
| public class ActionLink extends AbstractLink { |
| |
| // Constants -------------------------------------------------------------- |
| |
| private static final long serialVersionUID = 1L; |
| |
| /** The action link parameter name: <tt>actionLink</tt>. */ |
| public static final String ACTION_LINK = "actionLink"; |
| |
| /** The value parameter name: <tt>value</tt>. */ |
| public static final String VALUE = "value"; |
| |
| // Instance Variables ----------------------------------------------------- |
| |
| /** The link is clicked. */ |
| protected boolean clicked; |
| |
| // Constructors ----------------------------------------------------------- |
| |
| /** |
| * Create an ActionLink for the given name. |
| * <p/> |
| * Please note the name 'actionLink' is reserved as a control request |
| * parameter name and cannot be used as the name of the control. |
| * |
| * @param name the action link name |
| * @throws IllegalArgumentException if the name is null |
| */ |
| public ActionLink(String name) { |
| setName(name); |
| } |
| |
| /** |
| * Create an ActionLink for the given name and label. |
| * <p/> |
| * Please note the name 'actionLink' is reserved as a control request |
| * parameter name and cannot be used as the name of the control. |
| * |
| * @param name the action link name |
| * @param label the action link label |
| * @throws IllegalArgumentException if the name is null |
| */ |
| public ActionLink(String name, String label) { |
| setName(name); |
| setLabel(label); |
| } |
| |
| /** |
| * Create an ActionLink for the given listener object and listener |
| * method. |
| * |
| * @param listener the listener target object |
| * @param method the listener method to call |
| * @throws IllegalArgumentException if the name, listener or method is null |
| * or if the method is blank |
| */ |
| public ActionLink(Object listener, String method) { |
| if (listener == null) { |
| throw new IllegalArgumentException("Null listener parameter"); |
| } |
| if (StringUtils.isBlank(method)) { |
| throw new IllegalArgumentException("Blank listener method"); |
| } |
| setListener(listener, method); |
| } |
| |
| /** |
| * Create an ActionLink for the given name, listener object and listener |
| * method. |
| * <p/> |
| * Please note the name 'actionLink' is reserved as a control request |
| * parameter name and cannot be used as the name of the control. |
| * |
| * @param name the action link name |
| * @param listener the listener target object |
| * @param method the listener method to call |
| * @throws IllegalArgumentException if the name, listener or method is null |
| * or if the method is blank |
| */ |
| public ActionLink(String name, Object listener, String method) { |
| setName(name); |
| if (listener == null) { |
| throw new IllegalArgumentException("Null listener parameter"); |
| } |
| if (StringUtils.isBlank(method)) { |
| throw new IllegalArgumentException("Blank listener method"); |
| } |
| setListener(listener, method); |
| } |
| |
| /** |
| * Create an ActionLink for the given name, label, listener object and |
| * listener method. |
| * <p/> |
| * Please note the name 'actionLink' is reserved as a control request |
| * parameter name and cannot be used as the name of the control. |
| * |
| * @param name the action link name |
| * @param label the action link label |
| * @param listener the listener target object |
| * @param method the listener method to call |
| * @throws IllegalArgumentException if the name, listener or method is null |
| * or if the method is blank |
| */ |
| public ActionLink(String name, String label, Object listener, |
| String method) { |
| |
| setName(name); |
| setLabel(label); |
| if (listener == null) { |
| throw new IllegalArgumentException("Null listener parameter"); |
| } |
| if (StringUtils.isBlank(method)) { |
| throw new IllegalArgumentException("Blank listener method"); |
| } |
| setListener(listener, method); |
| } |
| |
| /** |
| * Create an ActionLink with no name defined. <b>Please note</b> the |
| * control's name must be defined before it is valid. |
| */ |
| public ActionLink() { |
| } |
| |
| // Public Attributes ------------------------------------------------------ |
| |
| /** |
| * Returns true if the ActionLink was clicked, otherwise returns false. |
| * |
| * @return true if the ActionLink was clicked, otherwise returns false. |
| */ |
| public boolean isClicked() { |
| return clicked; |
| } |
| |
| /** |
| * Return the ActionLink anchor <a> tag href attribute for the |
| * given value. This method will encode the URL with the session ID |
| * if required using <tt>HttpServletResponse.encodeURL()</tt>. |
| * |
| * @param value the ActionLink value parameter |
| * @return the ActionLink HTML href attribute |
| */ |
| public String getHref(Object value) { |
| Context context = getContext(); |
| String uri = ClickUtils.getRequestURI(context.getRequest()); |
| |
| HtmlStringBuffer buffer = |
| new HtmlStringBuffer(uri.length() + getName().length() + 40); |
| |
| buffer.append(uri); |
| buffer.append("?"); |
| buffer.append(ACTION_LINK); |
| buffer.append("="); |
| buffer.append(getName()); |
| if (value != null) { |
| buffer.append("&"); |
| buffer.append(VALUE); |
| buffer.append("="); |
| buffer.append(ClickUtils.encodeUrl(value, context)); |
| } |
| |
| if (hasParameters()) { |
| for (String paramName : getParameters().keySet()) { |
| if (!paramName.equals(ACTION_LINK) && !paramName.equals(VALUE)) { |
| Object paramValue = getParameters().get(paramName); |
| |
| // Check for multivalued parameter |
| if (paramValue instanceof String[]) { |
| String[] paramValues = (String[]) paramValue; |
| for (int j = 0; j < paramValues.length; j++) { |
| buffer.append("&"); |
| buffer.append(paramName); |
| buffer.append("="); |
| buffer.append(ClickUtils.encodeUrl(paramValues[j], |
| context)); |
| } |
| } else { |
| if (paramValue != null) { |
| buffer.append("&"); |
| buffer.append(paramName); |
| buffer.append("="); |
| buffer.append(ClickUtils.encodeUrl(paramValue, |
| context)); |
| } |
| } |
| } |
| } |
| } |
| |
| return context.getResponse().encodeURL(buffer.toString()); |
| } |
| |
| /** |
| * Return the ActionLink anchor <a> tag href attribute value. |
| * |
| * @return the ActionLink anchor <a> tag HTML href attribute value |
| */ |
| @Override |
| public String getHref() { |
| return getHref(getValue()); |
| } |
| |
| /** |
| * Set the name of the Control. Each control name must be unique in the |
| * containing Page model or the containing Form. |
| * <p/> |
| * Please note the name 'actionLink' is reserved as a control request |
| * parameter name and cannot be used as the name of the control. |
| * |
| * @see org.apache.click.Control#setName(String) |
| * |
| * @param name of the control |
| * @throws IllegalArgumentException if the name is null |
| */ |
| @Override |
| public void setName(String name) { |
| if (ACTION_LINK.equals(name)) { |
| String msg = "Invalid name '" + ACTION_LINK + "'. This name is " |
| + "reserved for use as a control request parameter name"; |
| throw new IllegalArgumentException(msg); |
| } |
| super.setName(name); |
| } |
| |
| /** |
| * Set the parent of the ActionLink. |
| * |
| * @see org.apache.click.Control#setParent(Object) |
| * |
| * @param parent the parent of the Control |
| * @throws IllegalStateException if {@link #name} is not defined |
| * @throws IllegalArgumentException if the given parent instance is |
| * referencing <tt>this</tt> object: <tt>if (parent == this)</tt> |
| */ |
| @Override |
| public void setParent(Object parent) { |
| if (parent == this) { |
| throw new IllegalArgumentException("Cannot set parent to itself"); |
| } |
| if (getName() == null) { |
| String msg = "ActionLink name not defined."; |
| throw new IllegalArgumentException(msg); |
| } |
| this.parent = parent; |
| } |
| |
| /** |
| * Returns the ActionLink value if the action link was processed and has |
| * a value, or null otherwise. |
| * |
| * @return the ActionLink value if the ActionLink was processed |
| */ |
| public String getValue() { |
| return getParameter(VALUE); |
| } |
| |
| /** |
| * Returns the action link <tt>Double</tt> value if the action link was |
| * processed and has a value, or null otherwise. |
| * |
| * @return the action link <tt>Double</tt> value if the action link was processed |
| * |
| * @throws NumberFormatException if the value cannot be parsed into a Double |
| */ |
| public Double getValueDouble() { |
| String value = getValue(); |
| if (value != null) { |
| return Double.valueOf(value); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Returns the ActionLink <tt>Integer</tt> value if the ActionLink was |
| * processed and has a value, or null otherwise. |
| * |
| * @return the ActionLink <tt>Integer</tt> value if the action link was processed |
| * |
| * @throws NumberFormatException if the value cannot be parsed into an Integer |
| */ |
| public Integer getValueInteger() { |
| String value = getValue(); |
| if (value != null) { |
| return Integer.valueOf(value); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Returns the ActionLink <tt>Long</tt> value if the ActionLink was |
| * processed and has a value, or null otherwise. |
| * |
| * @return the ActionLink <tt>Long</tt> value if the action link was processed |
| * |
| * @throws NumberFormatException if the value cannot be parsed into a Long |
| */ |
| public Long getValueLong() { |
| String value = getValue(); |
| if (value != null) { |
| return Long.valueOf(value); |
| } else { |
| return null; |
| } |
| } |
| |
| /** |
| * Set the ActionLink value. |
| * |
| * @param value the ActionLink value |
| */ |
| public void setValue(String value) { |
| setParameter(VALUE, value); |
| } |
| |
| /** |
| * Set the value of the ActionLink using the given object. |
| * |
| * @param object the object value to set |
| */ |
| public void setValueObject(Object object) { |
| if (object != null) { |
| setValue(object.toString()); |
| } else { |
| setValue(null); |
| } |
| } |
| |
| /** |
| * This method binds the submitted request value to the ActionLink's |
| * value. |
| */ |
| @Override |
| public void bindRequestValue() { |
| Context context = getContext(); |
| if (context.isMultipartRequest()) { |
| return; |
| } |
| |
| clicked = getName().equals(context.getRequestParameter(ACTION_LINK)); |
| |
| if (clicked) { |
| String value = context.getRequestParameter(VALUE); |
| if (value != null) { |
| setValue(value); |
| } |
| bindRequestParameters(context); |
| } |
| } |
| |
| // Public Methods --------------------------------------------------------- |
| |
| /** |
| * This method will set the {@link #isClicked()} property to true if the |
| * ActionLink was clicked, and if an action callback listener was set |
| * this will be invoked. |
| * |
| * @see org.apache.click.Control#onProcess() |
| * |
| * @return true to continue Page event processing or false otherwise |
| */ |
| @Override |
| public boolean onProcess() { |
| bindRequestValue(); |
| |
| if (isClicked()) { |
| dispatchActionEvent(); |
| } |
| return true; |
| } |
| } |