/*
* $Id$
*
* 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.struts2.components;
import com.opensymphony.xwork2.util.ValueStack;
import org.apache.commons.lang3.StringUtils;
import org.apache.struts2.StrutsException;
import org.apache.struts2.views.annotations.StrutsTag;
import org.apache.struts2.views.annotations.StrutsTagAttribute;
import java.io.Writer;
/**
* <!-- START SNIPPET: javadoc -->
* <p>This tag can be used to parameterize other tags.<br>
* The include tag and bean tag are examples of such tags.
* </p>
*
* <p>
* The parameters can be added with or without a name as key.
* If the tag provides a name attribute the parameters are added using the
* {@link Component#addParameter(String, Object) addParamter} method.
* For unnamed parameters the Tag must implement the {@link UnnamedParametric} interface defined in
* this class (e.g. The TextTag does this).
* </p>
*
* <p>
* This tag has the following two paramters.
* </p>
* <!-- START SNIPPET: params -->
* <ul>
* <li>name (String) - the name of the parameter</li>
* <li>value (Object) - the value of the parameter</li>
* <li>suppressEmptyParameters (boolean) - whether to suppress this parameter if empty</li>
* </ul>
* <!-- END SNIPPET: params -->
* <p>
* <b>Note:</b>
* When you declare the param tag, the value can be defined in either a <tt>value</tt> attribute or
* as text between the start and end tag. Struts behaves a bit different according to these two situations.
* This is best illustrated using an example:
* <br><param name="color">blue</param> <-- (A) -->
* <br><param name="color" value="blue"/> <-- (B) -->
* <br>In the first situation (A) the value would be evaluated to the stack as a <tt>java.lang.String</tt> object.
* And in situation (B) the value would be evaluated to the stack as a <tt>java.lang.Object</tt> object.
* <br>For more information see <a href="https://issues.apache.org/jira/browse/WW-808">WW-808</a>.
* </p>
* <!-- END SNIPPET: javadoc -->
*
* <p><b>Examples</b></p>
* <!-- START SNIPPET: example -->
* <pre>
* <ui:component>
* <ui:param name="key" value="[0]"/>
* <ui:param name="value" value="[1]"/>
* <ui:param name="context" value="[2]"/>
* </ui:component>
* </pre>
*
* <p>
* Whether to suppress empty parameters:
* </p>
*
* <pre>
* <s:url action="eventAdd">
* <s:param name="bean.searchString" value="%{bean.searchString}" />
* <s:param name="bean.filter" value="%{bean.filter}" />
* <s:param name="bean.pageNum" value="%{pager.pageNumber}" suppressEmptyParameters="true" />
* </s:url>
* </pre>
* <!-- END SNIPPET: example -->
* <p>
* <!-- START SNIPPET: exampledescription -->
* where the key will be the identifier and the value the result of an OGNL expression run against the current
* ValueStack.
* <!-- END SNIPPET: exampledescription -->
* </p>
* <p>
* This second example demonstrates how the text tag can use parameters from this param tag.
* </p>
* <!-- START SNIPPET: example2 -->
* <pre>
* <s:text name="cart.total.cost">
* <s:param value="#session.cartTotal"/>
* </s:text>
* </pre>
* <!-- END SNIPPET: example2 -->
*
*
* @see Include
* @see Bean
* @see Text
*
*/
@StrutsTag(name="param", tldTagClass="org.apache.struts2.views.jsp.ParamTag", description="Parametrize other tags")
public class Param extends Component {
protected String name;
protected String value;
protected boolean suppressEmptyParameters;
public Param(ValueStack stack) {
super(stack);
}
public boolean end(Writer writer, String body) {
Component component = findAncestor(Component.class);
if (value != null) {
if (component instanceof UnnamedParametric) {
((UnnamedParametric) component).addParameter(findValue(value));
} else {
String name = findString(this.name);
if (name == null) {
throw new StrutsException("No name found for following expression: " + this.name);
}
Object value = findValue(this.value);
if (suppressEmptyParameters) {
if (value != null && StringUtils.isNotBlank(value.toString())) {
component.addParameter(name, value);
} else {
component.addParameter(name, null);
}
} else if (value == null || StringUtils.isBlank(value.toString())) {
component.addParameter(name, "");
} else {
component.addParameter(name, value);
}
}
} else {
if (component instanceof UnnamedParametric) {
((UnnamedParametric) component).addParameter(body);
} else {
if (!(suppressEmptyParameters && StringUtils.isBlank(body))) {
component.addParameter(findString(name), body);
} else {
component.addParameter(findString(name), null);
}
}
}
return super.end(writer, "");
}
public boolean usesBody() {
return true;
}
@StrutsTagAttribute(description="Name of Parameter to set")
public void setName(String name) {
this.name = name;
}
@StrutsTagAttribute(description="Value expression for Parameter to set", defaultValue="The value of evaluating provided name against stack")
public void setValue(String value) {
this.value = value;
}
@StrutsTagAttribute(description="Whether to suppress empty parameters", type="Boolean", defaultValue="false")
public void setSuppressEmptyParameters(boolean suppressEmptyParameters) {
this.suppressEmptyParameters = suppressEmptyParameters;
}
/**
* <p>
* Tags can implement this to support nested param tags without the <tt>name</tt> attribute.
* </p>
* <p>
* The {@link Text TextTag} uses this approach. For unnamed parameters an example is given in the class
* javadoc for {@link Param ParamTag}.
* </p>
*/
public interface UnnamedParametric {
/**
* Adds the given value as a parameter to the outer tag.
* @param value the value
*/
public void addParameter(Object value);
}
}