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.rest;
23
24 import static javax.servlet.http.HttpServletResponse.SC_NOT_MODIFIED;
25 import static javax.servlet.http.HttpServletResponse.SC_OK;
26
27 import java.io.IOException;
28 import java.io.StringWriter;
29 import java.util.HashMap;
30 import java.util.Map;
31 import java.util.Set;
32
33 import javax.servlet.http.HttpServletRequest;
34 import javax.servlet.http.HttpServletResponse;
35
36 import org.apache.struts2.ServletActionContext;
37 import org.apache.struts2.rest.handler.ContentTypeHandler;
38
39 import com.opensymphony.xwork2.ModelDriven;
40 import com.opensymphony.xwork2.config.entities.ActionConfig;
41 import com.opensymphony.xwork2.inject.Container;
42 import com.opensymphony.xwork2.inject.Inject;
43
44 /***
45 * Manages {@link ContentTypeHandler} instances and uses them to
46 * process results
47 */
48 public class DefaultContentTypeHandlerManager implements ContentTypeHandlerManager {
49
50 /*** ContentTypeHandlers keyed by the extension */
51 Map<String,ContentTypeHandler> handlersByExtension = new HashMap<String,ContentTypeHandler>();
52 /*** ContentTypeHandlers keyed by the content-type */
53 Map<String,ContentTypeHandler> handlersByContentType = new HashMap<String,ContentTypeHandler>();
54
55 String defaultExtension;
56
57 @Inject("struts.rest.defaultExtension")
58 public void setDefaultExtension(String name) {
59 this.defaultExtension = name;
60 }
61
62 @Inject
63 public void setContainer(Container container) {
64 Set<String> names = container.getInstanceNames(ContentTypeHandler.class);
65 for (String name : names) {
66 ContentTypeHandler handler = container.getInstance(ContentTypeHandler.class, name);
67
68 if (handler.getExtension() != null) {
69
70 String overrideName = container.getInstance(String.class, STRUTS_REST_HANDLER_OVERRIDE_PREFIX +handler.getExtension());
71 if (overrideName != null) {
72 if (!handlersByExtension.containsKey(handler.getExtension())) {
73 handler = container.getInstance(ContentTypeHandler.class, overrideName);
74 } else {
75
76 continue;
77 }
78 }
79 this.handlersByExtension.put(handler.getExtension(), handler);
80 }
81
82 if (handler.getContentType() != null) {
83 this.handlersByContentType.put(handler.getContentType(), handler);
84 }
85 }
86 }
87
88 /***
89 * Gets the handler for the request by looking at the request content type and extension
90 * @param req The request
91 * @return The appropriate handler
92 */
93 public ContentTypeHandler getHandlerForRequest(HttpServletRequest req) {
94 ContentTypeHandler handler = null;
95 String contentType = req.getContentType();
96 if (contentType != null) {
97 int index = contentType.indexOf(';');
98 if( index != -1)
99 contentType = contentType.substring(0,index).trim();
100 handler = handlersByContentType.get(contentType);
101 }
102
103 if (handler == null) {
104 String extension = findExtension(req.getRequestURI());
105 if (extension == null) {
106 extension = defaultExtension;
107 }
108 handler = handlersByExtension.get(extension);
109 }
110 return handler;
111 }
112
113 /***
114 * Gets the handler for the response by looking at the extension of the request
115 * @param req The request
116 * @return The appropriate handler
117 */
118 public ContentTypeHandler getHandlerForResponse(HttpServletRequest req, HttpServletResponse res) {
119 String extension = findExtension(req.getRequestURI());
120 if (extension == null) {
121 extension = defaultExtension;
122 }
123 return handlersByExtension.get(extension);
124 }
125
126 /***
127 * Handles the result using handlers to generate content type-specific content
128 *
129 * @param actionConfig The action config for the current request
130 * @param methodResult The object returned from the action method
131 * @param target The object to return, usually the action object
132 * @return The new result code to process
133 * @throws IOException If unable to write to the response
134 */
135 public String handleResult(ActionConfig actionConfig, Object methodResult, Object target)
136 throws IOException {
137 String resultCode = null;
138 HttpServletRequest req = ServletActionContext.getRequest();
139 HttpServletResponse res = ServletActionContext.getResponse();
140 if (target instanceof ModelDriven) {
141 target = ((ModelDriven)target).getModel();
142 }
143
144 boolean statusNotOk = false;
145 if (methodResult instanceof HttpHeaders) {
146 HttpHeaders info = (HttpHeaders) methodResult;
147 resultCode = info.apply(req, res, target);
148 if (info.getStatus() != SC_OK) {
149
150
151 if (info.getStatus() == SC_NOT_MODIFIED) {
152 target = null;
153 } else {
154 statusNotOk = true;
155 }
156
157 }
158 } else {
159 resultCode = (String) methodResult;
160 }
161
162
163 if (!statusNotOk && !"get".equalsIgnoreCase(req.getMethod())) {
164 target = null;
165 }
166
167 ContentTypeHandler handler = getHandlerForResponse(req, res);
168 if (handler != null) {
169 String extCode = resultCode+"-"+handler.getExtension();
170 if (actionConfig.getResults().get(extCode) != null) {
171 resultCode = extCode;
172 } else {
173 StringWriter writer = new StringWriter();
174 resultCode = handler.fromObject(target, resultCode, writer);
175 String text = writer.toString();
176 if (text.length() > 0) {
177 byte[] data = text.getBytes("UTF-8");
178 res.setContentLength(data.length);
179 res.setContentType(handler.getContentType());
180 res.getOutputStream().write(data);
181 res.getOutputStream().close();
182 }
183 }
184 }
185 return resultCode;
186
187 }
188
189 /***
190 * Finds the extension in the url
191 *
192 * @param url The url
193 * @return The extension
194 */
195 protected String findExtension(String url) {
196 int dotPos = url.lastIndexOf('.');
197 int slashPos = url.lastIndexOf('/');
198 if (dotPos > slashPos && dotPos > -1) {
199 return url.substring(dotPos+1);
200 }
201 return null;
202 }
203 }