1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.apache.struts2.dispatcher;
23
24 import java.util.HashMap;
25 import java.util.Iterator;
26 import java.util.Map;
27
28 import javax.servlet.http.HttpServletResponse;
29
30 import org.apache.struts2.ServletActionContext;
31
32 import com.opensymphony.xwork2.ActionContext;
33 import com.opensymphony.xwork2.ActionInvocation;
34 import com.opensymphony.xwork2.Result;
35 import com.opensymphony.xwork2.util.TextParseUtil;
36 import com.opensymphony.xwork2.util.ValueStack;
37
38
39 /***
40 * <!-- START SNIPPET: description -->
41 *
42 * A custom Result type for setting HTTP headers and status by optionally evaluating against the ValueStack.
43 * This result can also be used to send and error to the client.
44 *
45 * <!-- END SNIPPET: description -->
46 * <p/>
47 * <b>This result type takes the following parameters:</b>
48 *
49 * <!-- START SNIPPET: params -->
50 *
51 * <ul>
52 *
53 * <li><b>status</b> - the http servlet response status code that should be set on a response.</li>
54 *
55 * <li><b>parse</b> - true by default. If set to false, the headers param will not be parsed for Ognl expressions.</li>
56 *
57 * <li><b>headers</b> - header values.</li>
58 *
59 * <li><b>error</b> - the http servlet response error code that should be set on a response.</li>
60 *
61 * <li><b>errorMessage</b> - error message to be set on response if 'error' is set.</li>
62 * </ul>
63 *
64 * <!-- END SNIPPET: params -->
65 *
66 * <b>Example:</b>
67 *
68 * <pre><!-- START SNIPPET: example -->
69 * <result name="success" type="httpheader">
70 * <param name="status">204</param>
71 * <param name="headers.a">a custom header value</param>
72 * <param name="headers.b">another custom header value</param>
73 * </result>
74 *
75 * <result name="proxyRequired" type="httpheader">
76 * <param name="error">305</param>
77 * <param name="errorMessage">this action must be accessed through a prozy</param>
78 * </result>
79 * <!-- END SNIPPET: example --></pre>
80 *
81 */
82 public class HttpHeaderResult implements Result {
83
84 private static final long serialVersionUID = 195648957144219214L;
85
86 /*** The default parameter */
87 public static final String DEFAULT_PARAM = "status";
88
89
90 private boolean parse = true;
91 private Map<String,String> headers;
92 private int status = -1;
93 private int error = -1;
94 private String errorMessage;
95
96 public HttpHeaderResult() {
97 super();
98 headers = new HashMap<String,String>();
99 }
100
101 public HttpHeaderResult(int status) {
102 this();
103 this.status = status;
104 this.parse = false;
105 }
106
107
108 /***
109 * Sets the http servlet error code that should be set on the reponse
110 *
111 * @param error the Http error code
112 * @see javax.servlet.http.HttpServletResponse#sendError(int)
113 */
114 public void setError(int error) {
115 this.error = error;
116 }
117
118 /***
119 * Sets the error message that should be set on the reponse
120 *
121 * @param errorMessage error message send to the client
122 * @see javax.servlet.http.HttpServletResponse#sendError(int, String)
123 */
124 public void setErrorMessage(String errorMessage) {
125 this.errorMessage = errorMessage;
126 }
127
128 /***
129 * Returns a Map of all HTTP headers.
130 *
131 * @return a Map of all HTTP headers.
132 */
133 public Map getHeaders() {
134 return headers;
135 }
136
137 /***
138 * Sets whether or not the HTTP header values should be evaluated against the ValueStack (by default they are).
139 *
140 * @param parse <tt>true</tt> if HTTP header values should be evaluated agains the ValueStack, <tt>false</tt>
141 * otherwise.
142 */
143 public void setParse(boolean parse) {
144 this.parse = parse;
145 }
146
147 /***
148 * Sets the http servlet response status code that should be set on a response.
149 *
150 * @param status the Http status code
151 * @see javax.servlet.http.HttpServletResponse#setStatus(int)
152 */
153 public void setStatus(int status) {
154 this.status = status;
155 }
156
157 /***
158 * Adds an HTTP header to the response
159 * @param name
160 * @param value
161 */
162 public void addHeader(String name, String value) {
163 headers.put(name, value);
164 }
165
166 /***
167 * Sets the optional HTTP response status code and also re-sets HTTP headers after they've
168 * been optionally evaluated against the ValueStack.
169 *
170 * @param invocation an encapsulation of the action execution state.
171 * @throws Exception if an error occurs when re-setting the headers.
172 */
173 public void execute(ActionInvocation invocation) throws Exception {
174 HttpServletResponse response = ServletActionContext.getResponse();
175 ValueStack stack = ActionContext.getContext().getValueStack();
176
177 if (status != -1) {
178 response.setStatus(status);
179 } else if (error != -1) {
180 if (errorMessage != null) {
181 String finalMessage = parse ? TextParseUtil.translateVariables(
182 errorMessage, stack) : errorMessage;
183 response.sendError(error, finalMessage);
184 } else
185 response.sendError(error);
186 }
187
188 if (headers != null) {
189 for (Iterator iterator = headers.entrySet().iterator();
190 iterator.hasNext();) {
191 Map.Entry entry = (Map.Entry) iterator.next();
192 String value = (String) entry.getValue();
193 String finalValue = parse ? TextParseUtil.translateVariables(value, stack) : value;
194 response.addHeader((String) entry.getKey(), finalValue);
195 }
196 }
197 }
198 }