View Javadoc

1   /*
2    * $Id: DefaultContentTypeHandlerManager.java 780096 2009-05-29 20:22:09Z 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.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                  // Check for overriding handlers for the current extension
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                          // overriding handler has already been registered
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                 // Don't return content on a not modified
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         // Don't return any content for PUT, DELETE, and POST where there are no errors
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 }