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