View Javadoc

1   /*
2    * $Id: ContentTypeHandlerManager.java 651946 2008-04-27 13:41:38Z apetrelli $
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.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.ByteArrayOutputStream;
36  import java.io.IOException;
37  import java.io.StringWriter;
38  import java.util.HashMap;
39  import java.util.Map;
40  import java.util.Set;
41  
42  /***
43   * Manages {@link ContentTypeHandler} instances and uses them to
44   * process results
45   */
46  public class ContentTypeHandlerManager {
47  
48      Map<String,ContentTypeHandler> handlers = new HashMap<String,ContentTypeHandler>();
49      String defaultExtension;
50      public static final String STRUTS_REST_HANDLER_OVERRIDE_PREFIX = "struts.rest.handlerOverride.";
51  
52      @Inject("struts.rest.defaultExtension")
53      public void setDefaultExtension(String name) {
54          this.defaultExtension = name;
55      }
56  
57      @Inject
58      public void setContainer(Container container) {
59          Set<String> names = container.getInstanceNames(ContentTypeHandler.class);
60          for (String name : names) {
61              ContentTypeHandler handler = container.getInstance(ContentTypeHandler.class, name);
62  
63              // Check for overriding handlers for the current extension
64              String overrideName = container.getInstance(String.class, STRUTS_REST_HANDLER_OVERRIDE_PREFIX +handler.getExtension());
65              if (overrideName != null) {
66                  if (!handlers.containsKey(handler.getExtension())) {
67                      handler = container.getInstance(ContentTypeHandler.class, overrideName);
68                  } else {
69                      // overriding handler has already been registered
70                      continue;
71                  }
72              }
73              this.handlers.put(handler.getExtension(), handler);
74          }
75      }
76      
77      /***
78       * Gets the handler for the request by looking at the extension
79       * @param req The request
80       * @return The appropriate handler
81       */
82      public ContentTypeHandler getHandlerForRequest(HttpServletRequest req) {
83          String extension = findExtension(req.getRequestURI());
84          if (extension == null) {
85              extension = defaultExtension;
86          }
87          return handlers.get(extension);
88      }
89      
90      /***
91       * Handles the result using handlers to generate content type-specific content
92       * 
93       * @param actionConfig The action config for the current request
94       * @param methodResult The object returned from the action method
95       * @param target The object to return, usually the action object
96       * @return The new result code to process
97       * @throws IOException If unable to write to the response
98       */
99      public String handleResult(ActionConfig actionConfig, Object methodResult, Object target)
100             throws IOException {
101         String resultCode = null;
102         HttpServletRequest req = ServletActionContext.getRequest();
103         HttpServletResponse res = ServletActionContext.getResponse();
104         if (target instanceof ModelDriven) {
105             target = ((ModelDriven)target).getModel();
106         }
107 
108         boolean statusNotOk = false;
109         if (methodResult instanceof HttpHeaders) {
110             HttpHeaders info = (HttpHeaders) methodResult;
111             resultCode = info.apply(req, res, target);
112             if (info.getStatus() != SC_OK) {
113 
114                 // Don't return content on a not modified
115                 if (info.getStatus() == SC_NOT_MODIFIED) {
116                     target = null;
117                 } else {
118                     statusNotOk = true;
119                 }
120 
121             }
122         } else {
123             resultCode = (String) methodResult;
124         }
125         
126         // Don't return any content for PUT, DELETE, and POST where there are no errors
127         if (!statusNotOk && !"get".equalsIgnoreCase(req.getMethod())) {
128             target = null;
129         }
130 
131         ContentTypeHandler handler = getHandlerForRequest(req);
132         if (handler != null) {
133             String extCode = resultCode+"-"+handler.getExtension();
134             if (actionConfig.getResults().get(extCode) != null) {
135                 resultCode = extCode;
136             } else {
137                 StringWriter writer = new StringWriter();
138                 resultCode = handler.fromObject(target, resultCode, writer);
139                 String text = writer.toString();
140                 if (text.length() > 0) {
141                     byte[] data = text.getBytes("UTF-8");
142                     res.setContentLength(data.length);
143                     res.setContentType(handler.getContentType());
144                     res.getOutputStream().write(data);
145                     res.getOutputStream().close();
146                 }
147             }
148         }
149         return resultCode;
150         
151     }
152     
153     /***
154      * Finds the extension in the url
155      * 
156      * @param url The url
157      * @return The extension
158      */
159     protected String findExtension(String url) {
160         int dotPos = url.lastIndexOf('.');
161         int slashPos = url.lastIndexOf('/');
162         if (dotPos > slashPos && dotPos > -1) {
163             return url.substring(dotPos+1);
164         }
165         return null;
166     }
167 }