View Javadoc

1   /*
2    * $Id: Anchor.java 757826 2009-03-24 14:53:29Z wesw $
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  package org.apache.struts2.components;
23  
24  import com.opensymphony.xwork2.inject.Inject;
25  import com.opensymphony.xwork2.util.ValueStack;
26  import com.opensymphony.xwork2.util.logging.Logger;
27  import com.opensymphony.xwork2.util.logging.LoggerFactory;
28  import org.apache.struts2.StrutsConstants;
29  import org.apache.struts2.views.annotations.StrutsTag;
30  import org.apache.struts2.views.annotations.StrutsTagAttribute;
31  import org.apache.commons.lang.xwork.StringUtils;
32  
33  import javax.servlet.http.HttpServletRequest;
34  import javax.servlet.http.HttpServletResponse;
35  import java.io.StringWriter;
36  import java.io.Writer;
37  import java.util.Map;
38  import java.util.LinkedHashMap;
39  
40  /***
41   * <!-- START SNIPPET: javadoc -->
42   * <p/>
43   * A tag that creates a HTML &lt;a &gt;.This tag supports the same attributes as the "url" tag,
44   * including nested parameters using the "param" tag.<p/>
45   * <!-- END SNIPPET: javadoc -->
46   * <p/>
47   * <p/> <b>Examples</b>
48   * <p/>
49   * <pre>
50   * <!-- START SNIPPET: example1 -->
51   * &lt;s:a id="link1" theme="ajax" href="/DoIt.action"&gt;
52   *     &lt;img border="none" src="&lt;%=request.getContextPath()%&gt;/images/delete.gif"/&gt;
53   *     &lt;s:param name="id" value="1"/&gt;
54   * &lt;/s:a&gt;
55   * <!-- END SNIPPET: example1 -->
56   * </pre>
57   */
58  @StrutsTag(
59          name = "a",
60          tldTagClass = "org.apache.struts2.views.jsp.ui.AnchorTag",
61          description = "Render a HTML href element that when clicked can optionally call a URL via remote XMLHttpRequest and updates its targets",
62          allowDynamicAttributes = true)
63  public class Anchor extends ClosingUIBean {
64      private static final Logger LOG = LoggerFactory.getLogger(Anchor.class);
65  
66      public static final String OPEN_TEMPLATE = "a";
67      public static final String TEMPLATE = "a-close";
68      public static final String COMPONENT_NAME = Anchor.class.getName();
69  
70      protected String href;
71      protected UrlProvider urlProvider;
72      protected UrlRenderer urlRenderer;
73      protected boolean processingTagBody = false;
74      
75      //these params are passed by the Param tag
76      protected Map urlParameters = new LinkedHashMap();
77  
78      public Anchor(ValueStack stack, HttpServletRequest request, HttpServletResponse response) {
79          super(stack, request, response);
80          urlProvider = new ComponentUrlProvider(this, this.urlParameters);
81          urlProvider.setHttpServletRequest(request);
82          urlProvider.setHttpServletResponse(response);
83      }
84  
85      public String getDefaultOpenTemplate() {
86          return OPEN_TEMPLATE;
87      }
88  
89      protected String getDefaultTemplate() {
90          return TEMPLATE;
91      }
92  
93      public boolean usesBody() {
94          return true;
95      }
96  
97      @Override
98      protected void evaluateExtraParams() {
99          super.evaluateExtraParams();
100 
101         if (href != null)
102             addParameter("href", ensureAttributeSafelyNotEscaped(findString(href)));
103         else {
104             //no href, build it from URL attributes
105             StringWriter sw = new StringWriter();
106             urlRenderer.beforeRenderUrl(urlProvider);
107             urlRenderer.renderUrl(sw, urlProvider);
108             String builtHref = sw.toString();
109             if (StringUtils.isNotEmpty(builtHref))
110                 addParameter("href", ensureAttributeSafelyNotEscaped(builtHref));
111         }
112     }
113 
114     @Inject(StrutsConstants.STRUTS_URL_INCLUDEPARAMS)
115     public void setUrlIncludeParams(String urlIncludeParams) {
116        urlProvider.setUrlIncludeParams(urlIncludeParams);
117     }
118 
119     @Inject
120 	public void setUrlRenderer(UrlRenderer urlRenderer) {
121 		urlProvider.setUrlRenderer(urlRenderer);
122         this.urlRenderer = urlRenderer;
123 	}
124 
125     @Inject(required=false)
126     public void setExtraParameterProvider(ExtraParameterProvider provider) {
127         urlProvider.setExtraParameterProvider(provider);
128     }
129 
130     @Override
131     public boolean start(Writer writer) {
132         boolean result = super.start(writer);
133         this.processingTagBody = true;
134         return result;
135     }
136 
137     /***
138      * Overrides to be able to render body in a template rather than always before the template
139      */
140     public boolean end(Writer writer, String body) {
141         this.processingTagBody = false;
142         evaluateParams();
143         try {
144             addParameter("body", body);
145             mergeTemplate(writer, buildTemplateName(template, getDefaultTemplate()));
146         } catch (Exception e) {
147             LOG.error("error when rendering", e);
148         }
149         finally {
150             popComponentStack();
151         }
152 
153         return false;
154     }
155 
156 
157     public void addParameter(String key, Object value) {
158         /*
159           the parameters added by this method are used in the template. this method is also
160           called by Param to add params into ancestestor. This tag needs to keep both set of parameters
161           separated (You gotta keep 'em separated!)
162          */
163         if (processingTagBody) {
164             this.urlParameters.put(key, value);
165         } else
166             super.addParameter(key, value);
167     }
168 
169     @Override
170     public void addAllParameters(Map params) {
171         /*
172           the parameters added by this method are used in the template. this method is also
173           called by Param to add params into ancestestor. This tag needs to keep both set of parameters
174           separated (You gotta keep 'em separated!)
175          */
176         if (processingTagBody) {
177             this.urlParameters.putAll(params);
178         } else
179             super.addAllParameters(params);
180     }
181 
182     public UrlProvider getUrlProvider() {
183         return urlProvider;
184     }
185 
186     @StrutsTagAttribute(description = "The URL.")
187     public void setHref(String href) {
188         this.href = href;
189     }
190 
191     @StrutsTagAttribute(description = "The includeParams attribute may have the value 'none', 'get' or 'all'", defaultValue = "none")
192     public void setIncludeParams(String includeParams) {
193         urlProvider.setIncludeParams(includeParams);
194     }
195 
196     @StrutsTagAttribute(description = "Set scheme attribute")
197     public void setScheme(String scheme) {
198         urlProvider.setScheme(scheme);
199     }
200 
201     @StrutsTagAttribute(description = "The target value to use, if not using action")
202     public void setValue(String value) {
203         urlProvider.setValue(value);
204     }
205 
206     @StrutsTagAttribute(description = "The action to generate the URL for, if not using value")
207     public void setAction(String action) {
208         urlProvider.setAction(action);
209     }
210 
211     @StrutsTagAttribute(description = "The namespace to use")
212     public void setNamespace(String namespace) {
213         urlProvider.setNamespace(namespace);
214     }
215 
216     @StrutsTagAttribute(description = "The method of action to use")
217     public void setMethod(String method) {
218         urlProvider.setMethod(method);
219     }
220 
221     @StrutsTagAttribute(description = "Whether to encode parameters", type = "Boolean", defaultValue = "true")
222     public void setEncode(boolean encode) {
223         urlProvider.setEncode(encode);
224     }
225 
226     @StrutsTagAttribute(description = "Whether actual context should be included in URL", type = "Boolean", defaultValue = "true")
227     public void setIncludeContext(boolean includeContext) {
228         urlProvider.setIncludeContext(includeContext);
229     }
230 
231     @StrutsTagAttribute(description = "The resulting portlet mode")
232     public void setPortletMode(String portletMode) {
233         urlProvider.setPortletMode(portletMode);
234     }
235 
236     @StrutsTagAttribute(description = "The resulting portlet window state")
237     public void setWindowState(String windowState) {
238         urlProvider.setWindowState(windowState);
239     }
240 
241     @StrutsTagAttribute(description = "Specifies if this should be a portlet render or action URL. Default is \"render\". To create an action URL, use \"action\".")
242     public void setPortletUrlType(String portletUrlType) {
243         urlProvider.setPortletUrlType(portletUrlType);
244     }
245 
246     @StrutsTagAttribute(description = "The anchor for this URL")
247     public void setAnchor(String anchor) {
248         urlProvider.setAnchor(anchor);
249     }
250 
251     @StrutsTagAttribute(description = "Specifies whether to escape ampersand (&amp;) to (&amp;amp;) or not", type = "Boolean", defaultValue = "true")
252     public void setEscapeAmp(boolean escapeAmp) {
253         urlProvider.setEscapeAmp(escapeAmp);
254     }
255 
256     @StrutsTagAttribute(description = "Specifies whether to force the addition of scheme, host and port or not", type = "Boolean", defaultValue = "false")
257     public void setForceAddSchemeHostAndPort(boolean forceAddSchemeHostAndPort) {
258         urlProvider.setForceAddSchemeHostAndPort(forceAddSchemeHostAndPort);
259     }
260 }